Skip to content

Commit

Permalink
simplify code of app manage
Browse files Browse the repository at this point in the history
  • Loading branch information
BinTianqi committed Jan 17, 2024
1 parent 4454465 commit 0a60aff
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 92 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ android {
applicationId = "com.binbin.androidowner"
minSdk = 26
targetSdk = 34
versionCode = 1
versionName = "1.0"
versionCode = 2
versionName = "1.1"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
Expand Down
128 changes: 81 additions & 47 deletions app/src/main/java/com/binbin/androidowner/ApplicationManage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@ package com.binbin.androidowner

import android.app.admin.DevicePolicyManager
import android.content.ComponentName
import android.content.Context
import android.content.pm.PackageManager.NameNotFoundException
import android.os.Build.VERSION
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
Expand All @@ -18,70 +25,97 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp


@Composable
fun ApplicationManage(myDpm:DevicePolicyManager, myComponent:ComponentName){
fun ApplicationManage(myDpm:DevicePolicyManager, myComponent:ComponentName,myContext:Context){
var pkgName by remember { mutableStateOf("") }
Column(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
var isAppHidden by remember{ mutableStateOf(false) }
var isAppSuspended by remember{ mutableStateOf(false) }
var isAppUninstallBlock by remember{ mutableStateOf(false) }
var suspendedReply = ""
isAppHidden = try {
myDpm.isApplicationHidden(myComponent,pkgName)
}catch (e:SecurityException){
false
}
isAppUninstallBlock = try {
myDpm.isUninstallBlocked(myComponent,pkgName)
}catch (e:SecurityException){
false
}
try{
isAppSuspended = myDpm.isPackageSuspended(myComponent,pkgName)
}catch(e:NameNotFoundException){
suspendedReply = "应用不存在!"
isAppSuspended = false
}catch (e:SecurityException){
suspendedReply = "无权限"
isAppSuspended = false
}
Text("以下功能都需要DeviceOwner权限")
TextField(value = pkgName, onValueChange = {pkgName = it}, label = { Text("包名") })
Spacer(Modifier.padding(5.dp))
Row{
Button(onClick = { myDpm.setApplicationHidden(myComponent,pkgName,true); isAppHidden = myDpm.isApplicationHidden(myComponent,pkgName) },modifier = Modifier.padding(end = 8.dp)) {
Text("隐藏")
}
Button(onClick = { myDpm.setApplicationHidden(myComponent,pkgName,false); isAppHidden = myDpm.isApplicationHidden(myComponent,pkgName) }) {
Text("显示")
TextField(
value = pkgName,
onValueChange = {
pkgName = it
},
label = { Text("包名") }
)
val isSuspended = {
try{
myDpm.isPackageSuspended(myComponent,pkgName)
}catch(e:NameNotFoundException){
false
}
}
Text("应用隐藏:$isAppHidden ${if(isAppHidden){"(这个应用也许没有被安装)"}else{""}}")
Row{
Button(onClick = {myDpm.setPackagesSuspended(myComponent, arrayOf(pkgName),true); isAppSuspended = myDpm.isPackageSuspended(myComponent,pkgName)},modifier = Modifier.padding(end = 8.dp)) {
Text("停用")
AppManageItem(R.string.hide,R.string.isapphidden_desc,myDpm, {myDpm.isApplicationHidden(myComponent,pkgName)},
{b -> myDpm.setApplicationHidden(myComponent,pkgName,b)})
AppManageItem(R.string.suspend,R.string.place_holder,myDpm, isSuspended,
{b -> myDpm.setPackagesSuspended(myComponent, arrayOf(pkgName) ,b)})
/*AppManageItem(R.string.block_unins,R.string.sometimes_not_avaliable,myDpm, {myDpm.isUninstallBlocked(myComponent,pkgName)},
{b -> myDpm.setUninstallBlocked(myComponent,pkgName,b)})*/
Text("因为无法获取某个应用是否防卸载,无法使用开关控制防卸载")
Row {
Button(onClick = {myDpm.setUninstallBlocked(myComponent,pkgName,false)}) {
Text("取消防卸载")
}
Button(onClick = {myDpm.setPackagesSuspended(myComponent, arrayOf(pkgName),false); isAppSuspended = myDpm.isPackageSuspended(myComponent,pkgName)}) {
Text("启用")
Spacer(Modifier.padding(horizontal = 2.dp))
Button(onClick = {myDpm.setUninstallBlocked(myComponent,pkgName,true)}) {
Text("防卸载")
}
}
Text("应用停用:$isAppSuspended $suspendedReply")
Text("阻止卸载功能有可能出问题")
Row {
Button(onClick = { myDpm.setUninstallBlocked(myComponent, pkgName, true); isAppUninstallBlock = myDpm.isUninstallBlocked(myComponent,pkgName) },modifier = Modifier.padding(end = 8.dp)) {
Text("阻止卸载")
}
Button(onClick = { myDpm.setUninstallBlocked(myComponent, pkgName, false); isAppUninstallBlock = myDpm.isUninstallBlocked(myComponent,pkgName)}) {
Text("允许卸载")
if(VERSION.SDK_INT>=30){
AppManageItem(R.string.user_ctrl_disabled,R.string.user_ctrl_disabled_desc,myDpm, {pkgName in myDpm.getUserControlDisabledPackages(myComponent)},
{b->myDpm.setUserControlDisabledPackages(myComponent, mutableListOf(if(b){pkgName}else{null}))})
}
Spacer(Modifier.padding(5.dp))
}
}

@Composable
private fun AppManageItem(
itemName:Int,
itemDesc:Int,
myDpm: DevicePolicyManager,
getMethod:()->Boolean,
setMethod:(b:Boolean)->Unit
){
var isEnabled by remember{ mutableStateOf(false) }
if(myDpm.isDeviceOwnerApp("com.binbin.androidowner")){
isEnabled = getMethod()
}
Row(
modifier = Modifier
.fillMaxWidth()
.padding(5.dp)
.clip(RoundedCornerShape(15))
.background(color = MaterialTheme.colorScheme.primaryContainer)
.padding(8.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Column {
Text(
text = stringResource(itemName),
style = MaterialTheme.typography.titleLarge
)
if(itemDesc!=R.string.place_holder){
Text(stringResource(itemDesc))
}
}
Text("应用防卸载:$isAppUninstallBlock ${if(!isAppUninstallBlock){"(这个应用也许没有被安装)"}else{""}}")
Switch(
checked = isEnabled,
onCheckedChange = {
setMethod(!isEnabled)
isEnabled = getMethod()
},
enabled = myDpm.isDeviceOwnerApp("com.binbin.androidowner")
)
}
}
17 changes: 9 additions & 8 deletions app/src/main/java/com/binbin/androidowner/DeviceControl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ fun DeviceControl(myDpm: DevicePolicyManager, myComponent: ComponentName){
}

@Composable
fun DeviceCtrlItem(
private fun DeviceCtrlItem(
itemName:Int,
itemDesc:Int,
myDpm: DevicePolicyManager,
Expand Down Expand Up @@ -122,13 +122,14 @@ fun DeviceCtrlItem(
}
if(myDpm.isDeviceOwnerApp("com.binbin.androidowner")){
isEnabled = getMethod()
Switch(
checked = isEnabled,
onCheckedChange = {
setMethod(!isEnabled)
isEnabled=getMethod()
}
)
}
Switch(
checked = isEnabled,
onCheckedChange = {
setMethod(!isEnabled)
isEnabled=getMethod()
},
enabled = myDpm.isDeviceOwnerApp("com.binbin.androidowner")
)
}
}
6 changes: 3 additions & 3 deletions app/src/main/java/com/binbin/androidowner/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ fun MyScaffold(mainDpm:DevicePolicyManager, mainComponent:ComponentName, mainCon
){
composable(route = "HomePage", content = { HomePage(navCtrl,mainDpm,mainComponent)})
composable(route = "DeviceControl", content = { DeviceControl(mainDpm,mainComponent)})
composable(route = "Permissions", content = { DpmPermissions(mainDpm,mainComponent,mainContext)})
composable(route = "ApplicationManage", content = { ApplicationManage(mainDpm,mainComponent)})
composable(route = "Permissions", content = { DpmPermissions(mainDpm,mainComponent,mainContext,navCtrl)})
composable(route = "ApplicationManage", content = { ApplicationManage(mainDpm,mainComponent,mainContext)})
composable(route = "UserRestriction", content = { UserRestriction(mainDpm,mainComponent)})
}
}
Expand All @@ -140,7 +140,7 @@ fun MyScaffold(mainDpm:DevicePolicyManager, mainComponent:ComponentName, mainCon
fun HomePage(navCtrl:NavHostController,myDpm:DevicePolicyManager,myComponent:ComponentName){
val isda = myDpm.isAdminActive(myComponent)
val isdo = myDpm.isDeviceOwnerApp("com.binbin.androidowner")
val activated = if(isdo){"Device Owner 已激活"}else if(isda){"Device Admin已激活"}else{""} + "未激活"
val activated = if(isdo){"Device Owner 已激活"}else if(isda){"Device Admin已激活"}else{"未激活"}
Column {
Row(
modifier = Modifier
Expand Down
94 changes: 62 additions & 32 deletions app/src/main/java/com/binbin/androidowner/Permissions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import android.app.admin.DevicePolicyManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.widget.Toast
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.provider.Settings.Global
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
Expand All @@ -29,11 +30,14 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import androidx.core.app.ActivityCompat.startActivityForResult
import androidx.core.content.ContextCompat.startActivity
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController


@Composable
fun DpmPermissions(myDpm: DevicePolicyManager, myComponent: ComponentName, myContext:Context){
fun DpmPermissions(myDpm: DevicePolicyManager, myComponent: ComponentName, myContext:Context,navCtrl:NavHostController){
//da:DeviceAdmin do:DeviceOwner
val isda = myDpm.isAdminActive(myComponent)
val isdo = myDpm.isDeviceOwnerApp("com.binbin.androidowner")
Expand All @@ -58,7 +62,16 @@ fun DpmPermissions(myDpm: DevicePolicyManager, myComponent: ComponentName, myCon
Text(if(isda){"已激活"}else{"未激活"})
}
if(isda){
Button(onClick = {myDpm.removeActiveAdmin(myComponent)}) {
Button(
onClick = {
myDpm.removeActiveAdmin(myComponent)
navCtrl.navigate("HomePage") {
popUpTo(
navCtrl.graph.findStartDestination().id
) { saveState = true }
}
}
) {
Text("撤销")
}
}else{
Expand All @@ -79,47 +92,64 @@ fun DpmPermissions(myDpm: DevicePolicyManager, myComponent: ComponentName, myCon
) {
Column {
Text(text = "Device Owner", style = MaterialTheme.typography.titleLarge)
Text(if(isda){"已激活"}else{"未激活"})
Text(if(isdo){"已激活"}else{"未激活"})
}
if(isdo){
Button(onClick = {myDpm.clearDeviceOwnerApp("com.binbin.androidowner")}) {
Button(
onClick = {
myDpm.clearDeviceOwnerApp("com.binbin.androidowner")
navCtrl.navigate("HomePage") {
popUpTo(
navCtrl.graph.findStartDestination().id
) { saveState = true }
}
}
) {
Text("撤销")
}
}
}
if(isdo||isda){Text("注意!在这里撤销权限不会清除配置。比如:被停用的应用会保持停用状态")}
Spacer(Modifier.padding(5.dp))
if(!isda){
SelectionContainer {
Text("dpm set-active-admin com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver")
Column(
horizontalAlignment = Alignment.Start
) {
if(isdo||isda){Text("注意!在这里撤销权限不会清除配置。比如:被停用的应用会保持停用状态")}
Spacer(Modifier.padding(5.dp))
if(!isda){
Text("你可以在adb shell中使用以下命令激活Device Admin")
SelectionContainer {
Text("dpm set-active-admin com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver")
}
Text("或者进入设置 -> 安全 -> 更多安全设置 -> 设备管理应用 -> Android Owner")
}
}
if(!isdo){
SelectionContainer {
Text("dpm set-device-owner com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver")
if(!isdo){
Text("你可以在adb shell中使用以下命令激活Device Owner")
SelectionContainer {
Text("dpm set-device-owner com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver")
}
if(!isda){
Text("使用此命令也会激活Device Admin")
}
}
}
if(isdo){
var lockScrInfo by remember { mutableStateOf("") }
TextField(value = lockScrInfo, onValueChange = { lockScrInfo= it}, label = { Text("锁屏信息") })
Spacer(Modifier.padding(5.dp))
Button(onClick = {myDpm.setDeviceOwnerLockScreenInfo(myComponent,lockScrInfo)}) {
Text("设置锁屏DeviceOwner信息")
if(isdo){
var lockScrInfo by remember { mutableStateOf("") }
TextField(value = lockScrInfo, onValueChange = { lockScrInfo= it}, label = { Text("锁屏信息") })
Spacer(Modifier.padding(5.dp))
Button(onClick = {myDpm.setDeviceOwnerLockScreenInfo(myComponent,lockScrInfo)}) {
Text("设置锁屏DeviceOwner信息")
}
}
}

}
}

fun ActivateDeviceAdmin(myDpm: DevicePolicyManager,myComponent: ComponentName,myContext: Context){
if (!myDpm.isAdminActive(myComponent)) {
val intent = Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN)
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, myComponent)
intent.putExtra(
DevicePolicyManager.EXTRA_ADD_EXPLANATION,
"在这里激活Android Owner"
)
startActivity(myContext,intent,null)
} else {
Toast.makeText(myContext, "已经激活", Toast.LENGTH_SHORT).show()
}
val intent = Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN)
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, myComponent)
intent.putExtra(
DevicePolicyManager.EXTRA_ADD_EXPLANATION,
"在这里激活Android Owner"
)
intent.setFlags(FLAG_ACTIVITY_NEW_TASK)
startActivity(myContext,intent,null)
}
25 changes: 25 additions & 0 deletions app/src/main/java/com/binbin/androidowner/Security.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.binbin.androidowner

import android.app.admin.DevicePolicyManager
import android.content.ComponentName
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable

@Composable
fun Security(myDpm:DevicePolicyManager,myComponent:ComponentName){
Column {
Button(onClick = {myDpm.clearResetPasswordToken(myComponent)}) {
Text("清除重置密码令牌")
}
Button(onClick = {myDpm.setResetPasswordToken(myComponent, byteArrayOf(32))}) {
Text("设置重置密码令牌")
}
Text("不知道上面两个东西干啥用的")
Button(onClick = {myDpm.resetPassword(null,0)}) {
Text("清除密码")
}
}

}
Loading

1 comment on commit 0a60aff

@BinTianqi
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

打了个Security.kt的草稿,将会用于密码和证书相关操作
Screenshot_20240117_200251_minify

Please sign in to comment.