From b0535f54a56de508711f8fde74cfb93176da1b11 Mon Sep 17 00:00:00 2001 From: BinTianqi <1220958406@qq.com> Date: Mon, 5 Feb 2024 13:16:15 +0800 Subject: [PATCH] set maximum time to lock --- .../com/binbin/androidowner/DeviceControl.kt | 34 +++++++++----- .../com/binbin/androidowner/MainActivity.kt | 29 ++++-------- .../java/com/binbin/androidowner/Password.kt | 46 +++++++++---------- .../com/binbin/androidowner/Permissions.kt | 37 +++------------ .../java/com/binbin/androidowner/Receiver.kt | 13 +++--- app/src/main/res/values/strings.xml | 5 +- 6 files changed, 70 insertions(+), 94 deletions(-) diff --git a/app/src/main/java/com/binbin/androidowner/DeviceControl.kt b/app/src/main/java/com/binbin/androidowner/DeviceControl.kt index 88f7eb8..a60d34f 100644 --- a/app/src/main/java/com/binbin/androidowner/DeviceControl.kt +++ b/app/src/main/java/com/binbin/androidowner/DeviceControl.kt @@ -1,10 +1,12 @@ package com.binbin.androidowner +import android.app.admin.DeviceAdminReceiver import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManager.* import android.content.ComponentName import android.content.Context import android.os.Build.VERSION +import android.util.Log import android.widget.Toast import androidx.activity.ComponentActivity import androidx.compose.animation.AnimatedVisibility @@ -26,7 +28,6 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.ImeAction -import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp @@ -221,19 +222,23 @@ fun DeviceControl(){ var keyGuard by remember{mutableStateOf(false)} var blockAct by remember{mutableStateOf(false)} if(VERSION.SDK_INT>=30){lockTaskPolicyList.add(LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK)} - val refreshFeature = { - var calculate = myDpm.getLockTaskFeatures(myComponent) - if(VERSION.SDK_INT>=30&&calculate-lockTaskPolicyList[7]>=0){blockAct=true;calculate-=lockTaskPolicyList[7]} - if(calculate-lockTaskPolicyList[6]>=0){keyGuard=true;calculate-=lockTaskPolicyList[6]} - if(calculate-lockTaskPolicyList[5]>=0){globalAction=true;calculate-=lockTaskPolicyList[5]} - if(calculate-lockTaskPolicyList[4]>=0){overview=true;calculate-=lockTaskPolicyList[4]} - if(calculate-lockTaskPolicyList[3]>=0){home=true;calculate-=lockTaskPolicyList[3]} - if(calculate-lockTaskPolicyList[2]>=0){notifications=true;calculate-=lockTaskPolicyList[2]} - if(calculate-lockTaskPolicyList[1]>=0){sysInfo=true;calculate-=lockTaskPolicyList[1]} - } - Text(text = "锁定任务模式", style = typography.titleLarge, color = colorScheme.onPrimaryContainer) var inited by remember{mutableStateOf(false)} var custom by remember{mutableStateOf(false)} + val refreshFeature = { + var calculate = myDpm.getLockTaskFeatures(myComponent) + if(calculate!=0){ + if(VERSION.SDK_INT>=30&&calculate-lockTaskPolicyList[7]>=0){blockAct=true;calculate-=lockTaskPolicyList[7]} + if(calculate-lockTaskPolicyList[6]>=0){keyGuard=true;calculate-=lockTaskPolicyList[6]} + if(calculate-lockTaskPolicyList[5]>=0){globalAction=true;calculate-=lockTaskPolicyList[5]} + if(calculate-lockTaskPolicyList[4]>=0){overview=true;calculate-=lockTaskPolicyList[4]} + if(calculate-lockTaskPolicyList[3]>=0){home=true;calculate-=lockTaskPolicyList[3]} + if(calculate-lockTaskPolicyList[2]>=0){notifications=true;calculate-=lockTaskPolicyList[2]} + if(calculate-lockTaskPolicyList[1]>=0){sysInfo=true;calculate-=lockTaskPolicyList[1]} + }else{ + custom = false + } + } + Text(text = "锁定任务模式", style = typography.titleLarge, color = colorScheme.onPrimaryContainer) if(!inited){ refreshFeature();custom=myDpm.getLockTaskFeatures(myComponent)!=0;inited=true } Text(text = "在锁定任务模式下:", style = bodyTextStyle) RadioButtonItem("禁用全部",{!custom},{custom=false}) @@ -295,9 +300,11 @@ fun DeviceControl(){ ) Button( onClick = { + focusMgr.clearFocus() whitelist.add(inputPkg) myDpm.setLockTaskPackages(myComponent,whitelist.toTypedArray()) Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show() + inputPkg="" refreshWhitelist() }, modifier = Modifier.fillMaxWidth() @@ -306,6 +313,7 @@ fun DeviceControl(){ } Button( onClick = { + focusMgr.clearFocus() if(inputPkg in whitelist){ whitelist.remove(inputPkg) myDpm.setLockTaskPackages(myComponent,whitelist.toTypedArray()) @@ -313,6 +321,7 @@ fun DeviceControl(){ }else{ Toast.makeText(myContext, "不存在", Toast.LENGTH_SHORT).show() } + inputPkg="" refreshWhitelist() }, modifier = Modifier.fillMaxWidth() @@ -382,6 +391,7 @@ fun DeviceControl(){ if(isDeviceOwner(myDpm)){ SysUpdatePolicy() } + Column(modifier = sections(if(isSystemInDarkTheme()){ colorScheme.errorContainer}else{ colorScheme.errorContainer.copy(alpha = 0.6F)})) { diff --git a/app/src/main/java/com/binbin/androidowner/MainActivity.kt b/app/src/main/java/com/binbin/androidowner/MainActivity.kt index 3673779..aeceae1 100644 --- a/app/src/main/java/com/binbin/androidowner/MainActivity.kt +++ b/app/src/main/java/com/binbin/androidowner/MainActivity.kt @@ -4,13 +4,10 @@ import android.annotation.SuppressLint import android.app.admin.DevicePolicyManager import android.content.ComponentName import android.content.Context -import android.content.Intent -import android.net.Uri import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent -import androidx.activity.result.ActivityResultLauncher -import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.animation.* import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape @@ -95,14 +92,7 @@ fun MyScaffold(){ modifier = Modifier .padding(horizontal = 6.dp) .clip(RoundedCornerShape(50)) - .clickable(onClick = { - navCtrl.navigate("HomePage") { - popUpTo( - navCtrl.graph.findStartDestination().id - ) { saveState = true } - } - focusMgr.clearFocus() - }) + .clickable{ navCtrl.navigateUp(); focusMgr.clearFocus() } .padding(5.dp) ) } @@ -235,14 +225,15 @@ fun RadioButtonItem( textColor:Color = MaterialTheme.colorScheme.onBackground ){ val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE) + val isWear = sharedPref.getBoolean("isWear",false) Row(verticalAlignment = Alignment.CenterVertically,modifier = Modifier .fillMaxWidth() - .padding(vertical = if(sharedPref.getBoolean("isWear",false)){3.dp}else{0.dp}) + .padding(vertical = if(isWear){3.dp}else{0.dp}) .clip(RoundedCornerShape(25)) .clickable(onClick = operation) ) { - RadioButton(selected = selected(), onClick = operation,modifier=if(sharedPref.getBoolean("isWear",false)){Modifier.size(28.dp)}else{Modifier}) - Text(text = text, style = if(!sharedPref.getBoolean("isWear",false)){typography.bodyLarge}else{typography.bodyMedium}, color = textColor, + RadioButton(selected = selected(), onClick = operation,modifier=if(isWear){Modifier.size(28.dp)}else{Modifier}) + Text(text = text, style = if(!isWear){typography.bodyLarge}else{typography.bodyMedium}, color = textColor, modifier = Modifier.padding(bottom = 2.dp)) } } @@ -254,19 +245,19 @@ fun CheckBoxItem( textColor:Color = MaterialTheme.colorScheme.onBackground ){ val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE) + val isWear = sharedPref.getBoolean("isWear",false) Row(verticalAlignment = Alignment.CenterVertically,modifier = Modifier .fillMaxWidth() - .padding(vertical = if(sharedPref.getBoolean("isWear",false)){3.dp}else{0.dp}) + .padding(vertical = if(isWear){3.dp}else{0.dp}) .clip(RoundedCornerShape(25)) .clickable(onClick = operation) ) { Checkbox( checked = checked(), onCheckedChange = {operation()}, - modifier=if(sharedPref.getBoolean("isWear",false)){Modifier.size(28.dp)}else{Modifier} + modifier=if(isWear){Modifier.size(28.dp)}else{Modifier} ) - Text(text = text, style = if(!sharedPref.getBoolean("isWear",false)){typography.bodyLarge}else{typography.bodyMedium}, color = textColor, - modifier = Modifier.padding(bottom = 2.dp)) + Text(text = text, style = if(!isWear){typography.bodyLarge}else{typography.bodyMedium}, color = textColor, modifier = Modifier.padding(bottom = 2.dp)) } } diff --git a/app/src/main/java/com/binbin/androidowner/Password.kt b/app/src/main/java/com/binbin/androidowner/Password.kt index e51316e..4b4ab70 100644 --- a/app/src/main/java/com/binbin/androidowner/Password.kt +++ b/app/src/main/java/com/binbin/androidowner/Password.kt @@ -24,7 +24,6 @@ import androidx.compose.material3.MaterialTheme.typography import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.FocusManager import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager @@ -197,12 +196,14 @@ fun Password(){ } } - PasswordItem(R.string.max_pwd_fail,R.string.max_pwd_fail_desc,R.string.max_pwd_fail_textfield, myDpm,focusMgr,false, + PasswordItem(R.string.max_pwd_fail,R.string.max_pwd_fail_desc,R.string.max_pwd_fail_textfield, false, {myDpm.getMaximumFailedPasswordsForWipe(null).toString()},{ic -> myDpm.setMaximumFailedPasswordsForWipe(myComponent, ic.toInt()) }) - PasswordItem(R.string.pwd_timeout,R.string.pwd_timeout_desc,R.string.pwd_timeout_textfield, myDpm,focusMgr,true, + PasswordItem(R.string.pwd_timeout,R.string.pwd_timeout_desc,R.string.pwd_timeout_textfield,true, {myDpm.getPasswordExpiration(null).toString()},{ic -> myDpm.setPasswordExpirationTimeout(myComponent, ic.toLong()) }) - PasswordItem(R.string.pwd_history,R.string.pwd_history_desc,R.string.pwd_history_textfield,myDpm, focusMgr,true, + PasswordItem(R.string.pwd_history,R.string.pwd_history_desc,R.string.pwd_history_textfield,true, {myDpm.getPasswordHistoryLength(null).toString()},{ic -> myDpm.setPasswordHistoryLength(myComponent, ic.toInt()) }) + PasswordItem(R.string.max_time_to_lock,R.string.max_time_to_lock_desc,R.string.max_time_to_lock_textfield,true, + {myDpm.getMaximumTimeToLock(myComponent).toString()},{ic -> myDpm.setMaximumTimeToLock(myComponent,ic.toLong())}) if(VERSION.SDK_INT>=31){ Column(modifier = sections()) { @@ -408,21 +409,21 @@ private fun PasswordItem( itemName:Int, itemDesc:Int, textFieldLabel:Int, - myDpm:DevicePolicyManager, - focusMgr:FocusManager, allowZero:Boolean, getMethod:()->String, setMethod:(ic:String)->Unit ){ + val myContext = LocalContext.current + val myDpm = myContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager + val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE) + val isWear = sharedPref.getBoolean("isWear",false) + val focusMgr = LocalFocusManager.current Column(modifier = sections()) { var inputContent by remember{ mutableStateOf(if(isDeviceOwner(myDpm)){getMethod()}else{""}) } - var inputContentEdited by remember{ mutableStateOf(false) } - var ableToApply by remember{ mutableStateOf(true) } - val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE) + var ableToApply by remember{ mutableStateOf(inputContent!=""&&((inputContent=="0"&&allowZero)||inputContent!="0")) } Text(text = stringResource(itemName), style = typography.titleLarge,color = colorScheme.onPrimaryContainer) - Text(text= stringResource(itemDesc),modifier=Modifier.padding(vertical = 2.dp), - style = if(!sharedPref.getBoolean("isWear",false)){typography.bodyLarge}else{typography.bodyMedium}) - if(!sharedPref.getBoolean("isWear",false)){Spacer(Modifier.padding(vertical = 2.dp))} + Text(text= stringResource(itemDesc),modifier=Modifier.padding(vertical = 2.dp), style = if(!isWear){typography.bodyLarge}else{typography.bodyMedium}) + if(!isWear){Spacer(Modifier.padding(vertical = 2.dp))} Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween, @@ -433,25 +434,20 @@ private fun PasswordItem( label = { Text(stringResource(textFieldLabel))}, onValueChange = { inputContent = it - if(inputContent!=""&&((inputContent=="0"&&allowZero)||inputContent!="0")){ - inputContentEdited = inputContent!=getMethod() - ableToApply = true - }else{ - ableToApply = false - } + ableToApply = inputContent!=""&&((inputContent=="0"&&allowZero)||inputContent!="0") }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), enabled = isDeviceOwner(myDpm), - modifier = if(sharedPref.getBoolean("isWear",false)){Modifier.fillMaxWidth()}else{Modifier.fillMaxWidth(0.8F)} + modifier = if(isWear){Modifier.fillMaxWidth()}else{Modifier.fillMaxWidth(0.8F)} ) - if(!sharedPref.getBoolean("isWear",false)){ + if(!isWear){ IconButton( - onClick = { focusMgr.clearFocus() ; setMethod(inputContent) ; inputContentEdited=inputContent!=getMethod() }, + onClick = { focusMgr.clearFocus() ; setMethod(inputContent) }, enabled = isDeviceOwner(myDpm)&&ableToApply, colors = IconButtonDefaults.iconButtonColors( - contentColor = if(inputContentEdited){ colorScheme.onError}else{ colorScheme.onPrimary}, - containerColor = if(inputContentEdited){ colorScheme.error}else{ colorScheme.primary}, + contentColor = colorScheme.onPrimary, + containerColor = colorScheme.primary, disabledContentColor = Color.Transparent, disabledContainerColor = Color.Transparent ) @@ -459,9 +455,9 @@ private fun PasswordItem( Icon(imageVector = Icons.Outlined.Check, contentDescription = null) }} } - if(sharedPref.getBoolean("isWear",false)){ + if(isWear){ Button( - onClick = {focusMgr.clearFocus() ; setMethod(inputContent) ; inputContentEdited=inputContent!=getMethod()}, + onClick = {focusMgr.clearFocus() ; setMethod(inputContent)}, enabled = isDeviceOwner(myDpm)&&ableToApply, modifier = Modifier.fillMaxWidth() ) { diff --git a/app/src/main/java/com/binbin/androidowner/Permissions.kt b/app/src/main/java/com/binbin/androidowner/Permissions.kt index f7b5c56..4998bcc 100644 --- a/app/src/main/java/com/binbin/androidowner/Permissions.kt +++ b/app/src/main/java/com/binbin/androidowner/Permissions.kt @@ -31,7 +31,6 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.core.content.ContextCompat.startActivity -import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavHostController @@ -69,11 +68,7 @@ fun DpmPermissions(navCtrl:NavHostController){ Button( onClick = { myDpm.removeActiveAdmin(myComponent) - navCtrl.navigate("HomePage") { - popUpTo( - navCtrl.graph.findStartDestination().id - ) { saveState = true } - } + navCtrl.navigateUp() } ) { Text("撤销") @@ -109,11 +104,7 @@ fun DpmPermissions(navCtrl:NavHostController){ Button( onClick = { myDpm.clearProfileOwner(myComponent) - navCtrl.navigate("HomePage") { - popUpTo( - navCtrl.graph.findStartDestination().id - ) { saveState = true } - } + navCtrl.navigateUp() } ) { Text("撤销") @@ -150,11 +141,7 @@ fun DpmPermissions(navCtrl:NavHostController){ Button( onClick = { myDpm.clearDeviceOwnerApp("com.binbin.androidowner") - navCtrl.navigate("HomePage") { - popUpTo( - navCtrl.graph.findStartDestination().id - ) { saveState = true } - } + navCtrl.navigateUp() } ) { Text("撤销") @@ -330,11 +317,7 @@ fun DpmPermissions(navCtrl:NavHostController){ Button( onClick = { myDpm.removeActiveAdmin(myComponent) - navCtrl.navigate("HomePage") { - popUpTo( - navCtrl.graph.findStartDestination().id - ) { saveState = true } - } + navCtrl.navigateUp() }, colors = ButtonDefaults.buttonColors(contentColor = colorScheme.onError, containerColor = colorScheme.error), enabled = myDpm.isAdminActive(myComponent) @@ -345,11 +328,7 @@ fun DpmPermissions(navCtrl:NavHostController){ Button( onClick = { myDpm.clearProfileOwner(myComponent) - navCtrl.navigate("HomePage") { - popUpTo( - navCtrl.graph.findStartDestination().id - ) { saveState = true } - } + navCtrl.navigateUp() }, colors = ButtonDefaults.buttonColors(contentColor = colorScheme.onError, containerColor = colorScheme.error), enabled = isProfileOwner(myDpm) @@ -360,11 +339,7 @@ fun DpmPermissions(navCtrl:NavHostController){ Button( onClick = { myDpm.clearDeviceOwnerApp("com.binbin.androidowner") - navCtrl.navigate("HomePage") { - popUpTo( - navCtrl.graph.findStartDestination().id - ) { saveState = true } - } + navCtrl.navigateUp() }, colors = ButtonDefaults.buttonColors(contentColor = colorScheme.onError, containerColor = colorScheme.error), enabled = isDeviceOwner(myDpm) diff --git a/app/src/main/java/com/binbin/androidowner/Receiver.kt b/app/src/main/java/com/binbin/androidowner/Receiver.kt index 43efff7..c0b5e2a 100644 --- a/app/src/main/java/com/binbin/androidowner/Receiver.kt +++ b/app/src/main/java/com/binbin/androidowner/Receiver.kt @@ -1,9 +1,11 @@ package com.binbin.androidowner +import android.annotation.SuppressLint import android.app.admin.DeviceAdminReceiver import android.content.Context import android.content.Intent import android.os.Build +import android.os.Build.VERSION import android.widget.Toast class MyDeviceAdminReceiver : DeviceAdminReceiver() { @@ -11,10 +13,11 @@ class MyDeviceAdminReceiver : DeviceAdminReceiver() { super.onEnabled(context, intent) Toast.makeText(context, "已启用", Toast.LENGTH_SHORT).show() } - /*override fun onReceive(context: Context, intent: Intent) { + @SuppressLint("UnsafeProtectedBroadcastReceiver") + override fun onReceive(context: Context, intent: Intent) { super.onReceive(context, intent) - Toast.makeText(context, "已接收", Toast.LENGTH_SHORT).show() - }*/ + if(VERSION.SDK_INT>=26){ DeviceAdminReceiver().onNetworkLogsAvailable(context,intent,1234567890,20) } + } override fun onDisableRequested(context: Context, intent: Intent): CharSequence { Toast.makeText(context, "撤销授权", Toast.LENGTH_SHORT).show() return "这是取消时的提示" @@ -24,9 +27,7 @@ class MyDeviceAdminReceiver : DeviceAdminReceiver() { Toast.makeText(context, "已禁用", Toast.LENGTH_SHORT).show() } override fun onSystemUpdatePending(context: Context, intent: Intent, receivedTime: Long) { - if (Build.VERSION.SDK_INT < 26) { - return - } + if (VERSION.SDK_INT < 26) { return } Toast.makeText(context, "新的系统更新!", Toast.LENGTH_SHORT).show() } } \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index acd146e..b0f64ee 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -93,7 +93,7 @@ 错误次数 密码失效超时时间 超时后用户需重新设置密码(毫秒),0为无限制 - 超时时间 + 超时时间(ms) 密码历史记录长度 用户输入的密码不能与历史记录中的任何密码相同,0为无限制 历史记录长度 @@ -112,4 +112,7 @@ 实验性功能 网络日志记录 没啥用 + 屏幕超时 + 超时后锁屏(毫秒),0为由用户决定 + 超时时间(ms)