beautify UI

This commit is contained in:
BinTianqi
2024-01-16 22:19:27 +08:00
parent 5777c232bb
commit 445446554f
13 changed files with 322 additions and 153 deletions

View File

@@ -1,3 +1,26 @@
# 简介 # 简介
使用安卓的DeviceAdmin和DeviceOwner API管理你的设备 使用安卓的DeviceAdmin和DeviceOwner API管理你的设备
即将加入的功能:安装应用、卸载应用、清空应用数据
欢迎大家提交Issue
### 功能
- 添加用户限制
- 禁止使用蓝牙
- 禁止使用WiFi
- 禁止安装应用
- ......
- 管理应用
- 隐藏应用
- 停用应用
- 禁止卸载应用
- ......
- 设备控制
- 禁用相机
- 禁止截屏
- 隐藏状态栏
这个应用需要的权限十分敏感,如果操作不慎,可能会让你的设备丢失数据或者让你无法解锁你的设备
但是你无需担心,这个应用不是恶意软件

View File

@@ -4,6 +4,9 @@ import android.app.admin.DevicePolicyManager
import android.content.ComponentName import android.content.ComponentName
import android.content.pm.PackageManager.NameNotFoundException import android.content.pm.PackageManager.NameNotFoundException
import androidx.compose.foundation.layout.Column 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.layout.padding
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.Text import androidx.compose.material3.Text
@@ -13,13 +16,19 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@Composable @Composable
fun ApplicationManage(myDpm:DevicePolicyManager, myComponent:ComponentName){ fun ApplicationManage(myDpm:DevicePolicyManager, myComponent:ComponentName){
var pkgName by remember { mutableStateOf("") } var pkgName by remember { mutableStateOf("") }
Column(modifier = Modifier.padding(8.dp)) { Column(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
var isAppHidden by remember{ mutableStateOf(false) } var isAppHidden by remember{ mutableStateOf(false) }
var isAppSuspended by remember{ mutableStateOf(false) } var isAppSuspended by remember{ mutableStateOf(false) }
var isAppUninstallBlock by remember{ mutableStateOf(false) } var isAppUninstallBlock by remember{ mutableStateOf(false) }
@@ -45,26 +54,33 @@ fun ApplicationManage(myDpm:DevicePolicyManager, myComponent:ComponentName){
} }
Text("以下功能都需要DeviceOwner权限") Text("以下功能都需要DeviceOwner权限")
TextField(value = pkgName, onValueChange = {pkgName = it}, label = { Text("包名") }) TextField(value = pkgName, onValueChange = {pkgName = it}, label = { Text("包名") })
Button(onClick = { myDpm.setApplicationHidden(myComponent,pkgName,true); isAppHidden = myDpm.isApplicationHidden(myComponent,pkgName) }) { Spacer(Modifier.padding(5.dp))
Text("隐藏") Row{
} Button(onClick = { myDpm.setApplicationHidden(myComponent,pkgName,true); isAppHidden = myDpm.isApplicationHidden(myComponent,pkgName) },modifier = Modifier.padding(end = 8.dp)) {
Button(onClick = { myDpm.setApplicationHidden(myComponent,pkgName,false); isAppHidden = myDpm.isApplicationHidden(myComponent,pkgName) }) { Text("隐藏")
Text("显示") }
Button(onClick = { myDpm.setApplicationHidden(myComponent,pkgName,false); isAppHidden = myDpm.isApplicationHidden(myComponent,pkgName) }) {
Text("显示")
}
} }
Text("应用隐藏:$isAppHidden ${if(isAppHidden){"(这个应用也许没有被安装)"}else{""}}") Text("应用隐藏:$isAppHidden ${if(isAppHidden){"(这个应用也许没有被安装)"}else{""}}")
Button(onClick = {myDpm.setPackagesSuspended(myComponent, arrayOf(pkgName),true); isAppSuspended = myDpm.isPackageSuspended(myComponent,pkgName)}) { Row{
Text("停用") Button(onClick = {myDpm.setPackagesSuspended(myComponent, arrayOf(pkgName),true); isAppSuspended = myDpm.isPackageSuspended(myComponent,pkgName)},modifier = Modifier.padding(end = 8.dp)) {
} Text("停用")
Button(onClick = {myDpm.setPackagesSuspended(myComponent, arrayOf(pkgName),false); isAppSuspended = myDpm.isPackageSuspended(myComponent,pkgName)}) { }
Text("启用") Button(onClick = {myDpm.setPackagesSuspended(myComponent, arrayOf(pkgName),false); isAppSuspended = myDpm.isPackageSuspended(myComponent,pkgName)}) {
Text("启用")
}
} }
Text("应用停用:$isAppSuspended $suspendedReply") Text("应用停用:$isAppSuspended $suspendedReply")
Text("阻止卸载功能有可能出问题") Text("阻止卸载功能有可能出问题")
Button(onClick = { myDpm.setUninstallBlocked(myComponent, pkgName, true); isAppUninstallBlock = myDpm.isUninstallBlocked(myComponent,pkgName) }) { Row {
Text("阻止卸载") 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("允许卸载") Button(onClick = { myDpm.setUninstallBlocked(myComponent, pkgName, false); isAppUninstallBlock = myDpm.isUninstallBlocked(myComponent,pkgName)}) {
Text("允许卸载")
}
} }
Text("应用防卸载:$isAppUninstallBlock ${if(!isAppUninstallBlock){"(这个应用也许没有被安装)"}else{""}}") Text("应用防卸载:$isAppUninstallBlock ${if(!isAppUninstallBlock){"(这个应用也许没有被安装)"}else{""}}")
} }

View File

@@ -3,19 +3,33 @@ package com.binbin.androidowner
import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManager
import android.content.ComponentName import android.content.ComponentName
import android.os.Build import android.os.Build
import android.os.Build.VERSION
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Switch
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
@OptIn(ExperimentalFoundationApi::class) @OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
@@ -25,41 +39,31 @@ fun DeviceControl(myDpm: DevicePolicyManager, myComponent: ComponentName){
}catch(e:SecurityException){ }catch(e:SecurityException){
"没有权限" "没有权限"
} }
Column { Column(
Text("WiFi MAC: $wifimac") modifier = Modifier
var isCameraDisabled by remember{ mutableStateOf(myDpm.getCameraDisabled(null)) } .verticalScroll(rememberScrollState())
Button(onClick = {myDpm.setCameraDisabled(myComponent, true);isCameraDisabled = myDpm.getCameraDisabled(null)}) { .padding(bottom = 20.dp)
Text("禁用相机") ) {
DeviceCtrlItem(R.string.disable_cam,R.string.place_holder, myDpm,{myDpm.getCameraDisabled(null)},{b -> myDpm.setCameraDisabled(myComponent,b)})
DeviceCtrlItem(R.string.disable_scrcap,R.string.aosp_scrrec_also_work,myDpm,{myDpm.getScreenCaptureDisabled(null)},{b -> myDpm.setScreenCaptureDisabled(myComponent,b) })
if(VERSION.SDK_INT>=34){
DeviceCtrlItem(R.string.hide_status_bar,R.string.may_hide_notifi_icon_only,myDpm,{myDpm.isStatusBarDisabled},{b -> myDpm.setStatusBarDisabled(myComponent,b) })
} }
Button(onClick = {myDpm.setCameraDisabled(myComponent, false);isCameraDisabled = myDpm.getCameraDisabled(null)}) { if(VERSION.SDK_INT>=30){
Text("启用相机") DeviceCtrlItem(R.string.auto_time,R.string.place_holder,myDpm,{myDpm.getAutoTimeEnabled(myComponent)},{b -> myDpm.setAutoTimeEnabled(myComponent,b) })
DeviceCtrlItem(R.string.auto_timezone,R.string.place_holder,myDpm,{myDpm.getAutoTimeZoneEnabled(myComponent)},{b -> myDpm.setAutoTimeZoneEnabled(myComponent,b) })
} }
Text("AVD上没有相机未测试") DeviceCtrlItem(R.string.master_mute,R.string.place_holder,myDpm,{myDpm.isMasterVolumeMuted(myComponent)},{b -> myDpm.setMasterVolumeMuted(myComponent,b) })
Text("相机被禁用:$isCameraDisabled") DeviceCtrlItem(R.string.backup_service,R.string.place_holder,myDpm,{myDpm.isBackupServiceEnabled(myComponent)},{b -> myDpm.setBackupServiceEnabled(myComponent,b) })
var isScrCapDisabled by remember{ mutableStateOf(myDpm.getScreenCaptureDisabled(null)) } Text("隐藏状态栏需要API34")
Button(onClick = {myDpm.setScreenCaptureDisabled(myComponent,true);isScrCapDisabled = myDpm.getScreenCaptureDisabled(null)}) { Text("自动设置时间和自动设置时区需要API30")
Text("禁止截屏")
}
Button(onClick = {myDpm.setScreenCaptureDisabled(myComponent,false);isScrCapDisabled = myDpm.getScreenCaptureDisabled(null)}) {
Text("允许截屏")
}
Text("对AOSP的录屏也起作用")
Text("禁止截屏:$isScrCapDisabled")
Button(onClick = {myDpm.reboot(myComponent)}) { Button(onClick = {myDpm.reboot(myComponent)}) {
Text("重启") Text("重启")
} }
Button(onClick = {myDpm.lockNow()}) { Button(onClick = {myDpm.lockNow()}) {
Text("锁屏") Text("锁屏")
} }
var isMasterMuted by remember{ mutableStateOf(false) } Text("WiFi MAC: $wifimac")
isMasterMuted = try{ myDpm.isMasterVolumeMuted(myComponent) }catch(e:SecurityException){ false }
Button(onClick = {myDpm.setMasterVolumeMuted(myComponent,true);isMasterMuted=myDpm.isMasterVolumeMuted(myComponent)}) {
Text("全部静音")
}
Button(onClick = {myDpm.setMasterVolumeMuted(myComponent,false);isMasterMuted=myDpm.isMasterVolumeMuted(myComponent)}) {
Text("取消静音")
}
Text("静音:$isMasterMuted")
Text("以下功能需要长按按钮,作者并未测试") Text("以下功能需要长按按钮,作者并未测试")
Button( Button(
onClick = {}, onClick = {},
@@ -72,7 +76,7 @@ fun DeviceControl(myDpm: DevicePolicyManager, myComponent: ComponentName){
) { ) {
Text("WipeData") Text("WipeData")
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { if (VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
Button( Button(
modifier = Modifier modifier = Modifier
.combinedClickable(onClick = {}, onLongClick = {myDpm.wipeDevice(0)}), .combinedClickable(onClick = {}, onLongClick = {myDpm.wipeDevice(0)}),
@@ -87,3 +91,44 @@ fun DeviceControl(myDpm: DevicePolicyManager, myComponent: ComponentName){
} }
} }
} }
@Composable
fun DeviceCtrlItem(
itemName:Int,
itemDesc:Int,
myDpm: DevicePolicyManager,
getMethod:()->Boolean,
setMethod:(b:Boolean)->Unit
){
var isEnabled by remember{ mutableStateOf(false) }
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))
}
}
if(myDpm.isDeviceOwnerApp("com.binbin.androidowner")){
isEnabled = getMethod()
Switch(
checked = isEnabled,
onCheckedChange = {
setMethod(!isEnabled)
isEnabled=getMethod()
}
)
}
}
}

View File

@@ -5,7 +5,6 @@ import android.app.admin.DevicePolicyManager
import android.content.ComponentName import android.content.ComponentName
import android.content.Context import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.provider.CalendarContract.Colors
import android.view.View import android.view.View
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
@@ -15,8 +14,11 @@ import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.ArrowBack
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@@ -31,11 +33,11 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
@@ -47,8 +49,8 @@ import com.google.accompanist.systemuicontroller.rememberSystemUiController
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
getWindow().decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) window.decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
getWindow().decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE) window.decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
//getWindow().setStatusBarColor(Color.White) //getWindow().setStatusBarColor(Color.White)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val context = applicationContext val context = applicationContext
@@ -97,19 +99,37 @@ fun MyScaffold(mainDpm:DevicePolicyManager, mainComponent:ComponentName, mainCon
}, },
colors = TopAppBarDefaults.topAppBarColors( colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.surface containerColor = MaterialTheme.colorScheme.surface
) ),
navigationIcon = {
if(topBarName!=R.string.app_name){
Icon(
imageVector = Icons.Outlined.ArrowBack,
contentDescription = "Back",
modifier = Modifier
.padding(horizontal = 6.dp)
.clip(RoundedCornerShape(50))
.clickable(onClick = {
navCtrl.navigate("HomePage") {
popUpTo(
navCtrl.graph.findStartDestination().id
) { saveState = true }
}
})
.padding(5.dp)
)
}
}
) )
} }
) { ) {
NavHost( NavHost(
navController = navCtrl, navController = navCtrl,
startDestination = "HomePage", startDestination = "HomePage",
modifier = Modifier.padding(top = it.calculateTopPadding()) modifier = Modifier.padding(top = it.calculateTopPadding()).navigationBarsPadding()
){ ){
composable(route = "HomePage", content = { HomePage(navCtrl)}) composable(route = "HomePage", content = { HomePage(navCtrl,mainDpm,mainComponent)})
composable(route = "DeviceControl", content = { DeviceControl(mainDpm,mainComponent)}) composable(route = "DeviceControl", content = { DeviceControl(mainDpm,mainComponent)})
composable(route = "Permissions", content = { DpmPermissions(mainDpm,mainComponent,mainContext)}) composable(route = "Permissions", content = { DpmPermissions(mainDpm,mainComponent,mainContext)})
composable(route = "UIControl", content = { UIControl(mainDpm,mainComponent)})
composable(route = "ApplicationManage", content = { ApplicationManage(mainDpm,mainComponent)}) composable(route = "ApplicationManage", content = { ApplicationManage(mainDpm,mainComponent)})
composable(route = "UserRestriction", content = { UserRestriction(mainDpm,mainComponent)}) composable(route = "UserRestriction", content = { UserRestriction(mainDpm,mainComponent)})
} }
@@ -117,13 +137,47 @@ fun MyScaffold(mainDpm:DevicePolicyManager, mainComponent:ComponentName, mainCon
} }
@Composable @Composable
fun HomePage(navCtrl:NavHostController){ 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{""} + "未激活"
Column { Column {
HomePageItem(R.string.permission, R.drawable.security_fill0, R.string.permission_desc, "Permissions", navCtrl) Row(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 5.dp, horizontal = 8.dp)
.clip(RoundedCornerShape(15))
.background(color = MaterialTheme.colorScheme.tertiaryContainer)
.clickable(onClick = { navCtrl.navigate("Permissions") })
.padding(horizontal = 5.dp, vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
painter = if(isda){
painterResource(R.drawable.check_fill0)
}else{
painterResource(R.drawable.block_fill0)
},
contentDescription = null,
modifier = Modifier.padding(horizontal = 13.dp),
tint = MaterialTheme.colorScheme.tertiary
)
Column {
Text(
text = stringResource(R.string.permission),
style = MaterialTheme.typography.headlineSmall,
color = MaterialTheme.colorScheme.onTertiaryContainer
)
Text(
text = activated,
color = MaterialTheme.colorScheme.onTertiaryContainer
)
}
}
//HomePageItem(R.string.permission, R.drawable.security_fill0, R.string.permission_desc, "Permissions", navCtrl)
HomePageItem(R.string.device_ctrl, R.drawable.mobile_phone_fill0, R.string.device_ctrl_desc, "DeviceControl", navCtrl) HomePageItem(R.string.device_ctrl, R.drawable.mobile_phone_fill0, R.string.device_ctrl_desc, "DeviceControl", navCtrl)
HomePageItem(R.string.ui_ctrl, R.drawable.info_fill0, R.string.ui_ctrl_desc, "UIControl", navCtrl) HomePageItem(R.string.app_manage, R.drawable.apps_fill0, R.string.apps_ctrl_description, "ApplicationManage", navCtrl)
HomePageItem(R.string.app_manage, R.drawable.info_fill0, R.string.apps_ctrl_description, "ApplicationManage", navCtrl) HomePageItem(R.string.user_restrict, R.drawable.manage_accounts_fill0, R.string.user_restrict_desc, "UserRestriction", navCtrl)
HomePageItem(R.string.user_restrict, R.drawable.info_fill0, R.string.user_restrict_desc, "UserRestriction", navCtrl)
} }
} }
@@ -136,7 +190,7 @@ fun HomePageItem(name:Int, imgVector:Int, description:Int, navTo:String, myNav:N
.clip(RoundedCornerShape(15)) .clip(RoundedCornerShape(15))
.background(color = MaterialTheme.colorScheme.primaryContainer) .background(color = MaterialTheme.colorScheme.primaryContainer)
.clickable(onClick = { myNav.navigate(navTo) }) .clickable(onClick = { myNav.navigate(navTo) })
.padding(5.dp), .padding(6.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Icon( Icon(

View File

@@ -6,8 +6,11 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.widget.Toast import android.widget.Toast
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
@@ -22,6 +25,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@@ -33,80 +37,76 @@ fun DpmPermissions(myDpm: DevicePolicyManager, myComponent: ComponentName, myCon
//da:DeviceAdmin do:DeviceOwner //da:DeviceAdmin do:DeviceOwner
val isda = myDpm.isAdminActive(myComponent) val isda = myDpm.isAdminActive(myComponent)
val isdo = myDpm.isDeviceOwnerApp("com.binbin.androidowner") val isdo = myDpm.isDeviceOwnerApp("com.binbin.androidowner")
val ispo = myDpm.isProfileOwnerApp("com.binbin.androidowner")
Column( Column(
modifier = Modifier modifier = Modifier
.padding(8.dp) .padding(8.dp)
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally
) { ) {
Text("权限DeviceAdmin < ProfileOwner < DeviceOwner") Row(
Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth()
.padding(bottom = 10.dp)
.clip(RoundedCornerShape(8)) .clip(RoundedCornerShape(8))
.background(color = MaterialTheme.colorScheme.primaryContainer) .background(color = MaterialTheme.colorScheme.primaryContainer)
.padding(10.dp) .padding(10.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) { ) {
Text(text = "Device Admin", style = MaterialTheme.typography.titleLarge) Column {
Text("Device Admin: $isda") Text(text = "Device Admin", style = MaterialTheme.typography.titleLarge)
Text(if(isda){"已激活"}else{"未激活"})
}
if(isda){
Button(onClick = {myDpm.removeActiveAdmin(myComponent)}) {
Text("撤销")
}
}else{
Button(onClick = { ActivateDeviceAdmin(myDpm, myComponent, myContext) }) {
Text("激活")
}
}
}
Row(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 10.dp)
.clip(RoundedCornerShape(8))
.background(color = MaterialTheme.colorScheme.primaryContainer)
.padding(10.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Column {
Text(text = "Device Owner", style = MaterialTheme.typography.titleLarge)
Text(if(isda){"已激活"}else{"未激活"})
}
if(isdo){
Button(onClick = {myDpm.clearDeviceOwnerApp("com.binbin.androidowner")}) {
Text("撤销")
}
}
}
if(isdo||isda){Text("注意!在这里撤销权限不会清除配置。比如:被停用的应用会保持停用状态")}
Spacer(Modifier.padding(5.dp))
if(!isda){
SelectionContainer { SelectionContainer {
Text("dpm set-active-admin com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver") Text("dpm set-active-admin com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver")
} }
Button(onClick = {Runtime.getRuntime().exec("su -c \"dpm set-active-admin com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver\"")}) {
Text("获取DeviceAdmin需root未测试")
}
Button(onClick = { ActivateDeviceAdmin(myDpm, myComponent, myContext) }) {
Text("在设置中激活DeviceAdmin")
}
Button(onClick = {myDpm.removeActiveAdmin(myComponent)}) {
Text("不当Device Admin了")
}
} }
Spacer(modifier = Modifier.padding(6.dp)) if(!isdo){
Column(
modifier = Modifier
.clip(RoundedCornerShape(8))
.background(color = MaterialTheme.colorScheme.primaryContainer)
.padding(10.dp)
) {
Text(text = "Device Owner", style = MaterialTheme.typography.titleLarge)
Text("Device Owner: $isdo")
SelectionContainer { SelectionContainer {
Text("dpm set-device-owner com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver") Text("dpm set-device-owner com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver")
} }
Button(onClick = {Runtime.getRuntime().exec("su -c \"dpm set-device-owner com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver\"")}) { }
Text("获取DeviceOwner需root未测试") if(isdo){
}
Button(onClick = {myDpm.clearDeviceOwnerApp("com.binbin.androidowner")}) {
Text("不当Device Owner了")
}
Text("注意!在这里清除权限不会清除配置。比如:被停用的应用会保持停用状态")
var lockScrInfo by remember { mutableStateOf("") } var lockScrInfo by remember { mutableStateOf("") }
TextField(value = lockScrInfo, onValueChange = { lockScrInfo= it}, label = { Text("锁屏信息") }) TextField(value = lockScrInfo, onValueChange = { lockScrInfo= it}, label = { Text("锁屏信息") })
Spacer(Modifier.padding(5.dp))
Button(onClick = {myDpm.setDeviceOwnerLockScreenInfo(myComponent,lockScrInfo)}) { Button(onClick = {myDpm.setDeviceOwnerLockScreenInfo(myComponent,lockScrInfo)}) {
Text("设置锁屏DeviceOwner信息") Text("设置锁屏DeviceOwner信息")
} }
} }
Spacer(modifier = Modifier.padding(6.dp))
Column(
modifier = Modifier
.clip(RoundedCornerShape(8))
.background(color = MaterialTheme.colorScheme.primaryContainer)
.padding(10.dp)
) {
Text("Profile Owner是一个过时的功能目前在这个应用里没啥用。")
Text(text = "Profile Owner", style = MaterialTheme.typography.titleLarge)
Text("Profile Owner: $ispo")
SelectionContainer {
Text("dpm set-profile-owner com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver")
}
Button(onClick = {Runtime.getRuntime().exec("su -c \"dpm set-profile-owner com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver\"")}) {
Text("获取ProfileOwner需root未测试")
}
Button(onClick = {myDpm.clearProfileOwner(myComponent)}) {
Text("不当Profile Owner了")
}
}
} }
} }
@@ -122,5 +122,4 @@ fun ActivateDeviceAdmin(myDpm: DevicePolicyManager,myComponent: ComponentName,my
} else { } else {
Toast.makeText(myContext, "已经激活", Toast.LENGTH_SHORT).show() Toast.makeText(myContext, "已经激活", Toast.LENGTH_SHORT).show()
} }
} }

View File

@@ -1,26 +0,0 @@
package com.binbin.androidowner
import android.app.admin.DevicePolicyManager
import android.content.ComponentName
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun UIControl(myDpm: DevicePolicyManager, myComponent: ComponentName){
Column(
modifier = Modifier.padding(8.dp)
) {
Button(onClick = {myDpm.setStatusBarDisabled(myComponent,true)}) {
Text("隐藏状态栏")
}
Button(onClick = {myDpm.setStatusBarDisabled(myComponent,false)}) {
Text("显示状态栏")
}
Text("也许只能控制状态栏上的通知图标")
}
}

View File

@@ -33,7 +33,11 @@ import androidx.compose.ui.unit.dp
@Composable @Composable
fun UserRestriction(myDpm: DevicePolicyManager, myComponent: ComponentName){ fun UserRestriction(myDpm: DevicePolicyManager, myComponent: ComponentName){
val verticalScrolling = rememberScrollState() val verticalScrolling = rememberScrollState()
Column(modifier = Modifier.verticalScroll(verticalScrolling)) { Column(
modifier = Modifier
.verticalScroll(verticalScrolling)
.padding(bottom = 20.dp)
) {
UserRestrictionItem(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,R.string.config_mobile_network,"",myComponent, myDpm) UserRestrictionItem(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,R.string.config_mobile_network,"",myComponent, myDpm)
UserRestrictionItem(UserManager.DISALLOW_CONFIG_WIFI,R.string.config_wifi,"",myComponent, myDpm) UserRestrictionItem(UserManager.DISALLOW_CONFIG_WIFI,R.string.config_wifi,"",myComponent, myDpm)
UserRestrictionItem(UserManager.DISALLOW_BLUETOOTH,R.string.bluetooth,"",myComponent, myDpm) UserRestrictionItem(UserManager.DISALLOW_BLUETOOTH,R.string.bluetooth,"",myComponent, myDpm)
@@ -96,19 +100,19 @@ private fun UserRestrictionItem(restriction:String, itemName:Int, restrictionDes
} }
if(isdo){ if(isdo){
strictState = myDpm.getUserRestrictions(myComponent).getBoolean(restriction) strictState = myDpm.getUserRestrictions(myComponent).getBoolean(restriction)
Switch(
checked = strictState,
onCheckedChange = {
strictState=it
if(strictState){
myDpm.addUserRestriction(myComponent,restriction)
}else{
myDpm.clearUserRestriction(myComponent,restriction)
}
strictState = myDpm.getUserRestrictions(myComponent).getBoolean(restriction)
},
enabled = isdo
)
} }
Switch(
checked = strictState,
onCheckedChange = {
strictState=it
if(strictState){
myDpm.addUserRestriction(myComponent,restriction)
}else{
myDpm.clearUserRestriction(myComponent,restriction)
}
strictState = myDpm.getUserRestrictions(myComponent).getBoolean(restriction)
},
enabled = isdo
)
} }
} }

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#FF000000"
android:pathData="M240,800q-33,0 -56.5,-23.5T160,720q0,-33 23.5,-56.5T240,640q33,0 56.5,23.5T320,720q0,33 -23.5,56.5T240,800ZM480,800q-33,0 -56.5,-23.5T400,720q0,-33 23.5,-56.5T480,640q33,0 56.5,23.5T560,720q0,33 -23.5,56.5T480,800ZM720,800q-33,0 -56.5,-23.5T640,720q0,-33 23.5,-56.5T720,640q33,0 56.5,23.5T800,720q0,33 -23.5,56.5T720,800ZM240,560q-33,0 -56.5,-23.5T160,480q0,-33 23.5,-56.5T240,400q33,0 56.5,23.5T320,480q0,33 -23.5,56.5T240,560ZM480,560q-33,0 -56.5,-23.5T400,480q0,-33 23.5,-56.5T480,400q33,0 56.5,23.5T560,480q0,33 -23.5,56.5T480,560ZM720,560q-33,0 -56.5,-23.5T640,480q0,-33 23.5,-56.5T720,400q33,0 56.5,23.5T800,480q0,33 -23.5,56.5T720,560ZM240,320q-33,0 -56.5,-23.5T160,240q0,-33 23.5,-56.5T240,160q33,0 56.5,23.5T320,240q0,33 -23.5,56.5T240,320ZM480,320q-33,0 -56.5,-23.5T400,240q0,-33 23.5,-56.5T480,160q33,0 56.5,23.5T560,240q0,33 -23.5,56.5T480,320ZM720,320q-33,0 -56.5,-23.5T640,240q0,-33 23.5,-56.5T720,160q33,0 56.5,23.5T800,240q0,33 -23.5,56.5T720,320Z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#FF000000"
android:pathData="M480,880q-83,0 -156,-31.5T197,763q-54,-54 -85.5,-127T80,480q0,-83 31.5,-156T197,197q54,-54 127,-85.5T480,80q83,0 156,31.5T763,197q54,54 85.5,127T880,480q0,83 -31.5,156T763,763q-54,54 -127,85.5T480,880ZM480,800q54,0 104,-17.5t92,-50.5L228,284q-33,42 -50.5,92T160,480q0,134 93,227t227,93ZM732,676q33,-42 50.5,-92T800,480q0,-134 -93,-227t-227,-93q-54,0 -104,17.5T284,228l448,448Z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#FF000000"
android:pathData="M382,720 L154,492l57,-57 171,171 367,-367 57,57 -424,424Z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#FF000000"
android:pathData="M400,480q-66,0 -113,-47t-47,-113q0,-66 47,-113t113,-47q66,0 113,47t47,113q0,66 -47,113t-113,47ZM80,800v-112q0,-33 17,-62t47,-44q51,-26 115,-44t141,-18h14q6,0 12,2 -8,18 -13.5,37.5T404,600h-4q-71,0 -127.5,18T180,654q-9,5 -14.5,14t-5.5,20v32h252q6,21 16,41.5t22,38.5L80,800ZM640,840 L628,780q-12,-5 -22.5,-10.5T584,756l-58,18 -40,-68 46,-40q-2,-14 -2,-26t2,-26l-46,-40 40,-68 58,18q11,-8 21.5,-13.5T628,500l12,-60h80l12,60q12,5 22.5,11t21.5,15l58,-20 40,70 -46,40q2,12 2,25t-2,25l46,40 -40,68 -58,-18q-11,8 -21.5,13.5T732,780l-12,60h-80ZM680,720q33,0 56.5,-23.5T760,640q0,-33 -23.5,-56.5T680,560q-33,0 -56.5,23.5T600,640q0,33 23.5,56.5T680,720ZM400,400q33,0 56.5,-23.5T480,320q0,-33 -23.5,-56.5T400,240q-33,0 -56.5,23.5T320,320q0,33 23.5,56.5T400,400ZM400,320ZM412,720Z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#FF000000"
android:pathData="M504,480 L320,296l56,-56 240,240 -240,240 -56,-56 184,-184Z"/>
</vector>

View File

@@ -31,4 +31,13 @@
<string name="autofill">自动填充服务</string> <string name="autofill">自动填充服务</string>
<string name="camera_toggle">切换相机</string> <string name="camera_toggle">切换相机</string>
<string name="bt_share">蓝牙分享</string> <string name="bt_share">蓝牙分享</string>
<string name="disable_cam">禁用相机</string>
<string name="disable_scrcap">禁止截屏</string>
<string name="master_mute">全局静音</string>
<string name="aosp_scrrec_also_work">对AOSP的录屏也起作用</string>
<string name="hide_status_bar">隐藏状态栏</string>
<string name="may_hide_notifi_icon_only">也许只能隐藏状态栏上的通知图标</string>
<string name="auto_time">自动设置时间</string>
<string name="auto_timezone">自动设置时区</string>
<string name="backup_service">备份服务</string>
</resources> </resources>