diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 47bb4c3..5614c0d 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -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 {
diff --git a/app/src/main/java/com/binbin/androidowner/ApplicationManage.kt b/app/src/main/java/com/binbin/androidowner/ApplicationManage.kt
index cbdf106..962f929 100644
--- a/app/src/main/java/com/binbin/androidowner/ApplicationManage.kt
+++ b/app/src/main/java/com/binbin/androidowner/ApplicationManage.kt
@@ -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
@@ -18,10 +25,13 @@ 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
@@ -29,59 +39,83 @@ fun ApplicationManage(myDpm:DevicePolicyManager, myComponent:ComponentName){
.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")
+ )
}
}
diff --git a/app/src/main/java/com/binbin/androidowner/DeviceControl.kt b/app/src/main/java/com/binbin/androidowner/DeviceControl.kt
index b110770..9ce6def 100644
--- a/app/src/main/java/com/binbin/androidowner/DeviceControl.kt
+++ b/app/src/main/java/com/binbin/androidowner/DeviceControl.kt
@@ -93,7 +93,7 @@ fun DeviceControl(myDpm: DevicePolicyManager, myComponent: ComponentName){
}
@Composable
-fun DeviceCtrlItem(
+private fun DeviceCtrlItem(
itemName:Int,
itemDesc:Int,
myDpm: DevicePolicyManager,
@@ -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")
+ )
}
}
diff --git a/app/src/main/java/com/binbin/androidowner/MainActivity.kt b/app/src/main/java/com/binbin/androidowner/MainActivity.kt
index dc5a781..2af3632 100644
--- a/app/src/main/java/com/binbin/androidowner/MainActivity.kt
+++ b/app/src/main/java/com/binbin/androidowner/MainActivity.kt
@@ -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)})
}
}
@@ -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
diff --git a/app/src/main/java/com/binbin/androidowner/Permissions.kt b/app/src/main/java/com/binbin/androidowner/Permissions.kt
index 87e1ced..d55cae8 100644
--- a/app/src/main/java/com/binbin/androidowner/Permissions.kt
+++ b/app/src/main/java/com/binbin/androidowner/Permissions.kt
@@ -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
@@ -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")
@@ -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{
@@ -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)
}
diff --git a/app/src/main/java/com/binbin/androidowner/Security.kt b/app/src/main/java/com/binbin/androidowner/Security.kt
new file mode 100644
index 0000000..d277653
--- /dev/null
+++ b/app/src/main/java/com/binbin/androidowner/Security.kt
@@ -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("清除密码")
+ }
+ }
+
+}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 8d5942f..ae647a7 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -40,4 +40,11 @@
自动设置时间
自动设置时区
备份服务
+ 隐藏
+ 停用
+ 防卸载
+ 如果隐藏,有可能是没安装
+ 有时候不能用
+ 禁止用户控制
+ 阻止清除应用数据和缓存>
\ No newline at end of file