set maximum time to lock

This commit is contained in:
BinTianqi
2024-02-05 13:16:15 +08:00
parent 5bc3f40d6e
commit b0535f54a5
6 changed files with 70 additions and 94 deletions

View File

@@ -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)})) {

View File

@@ -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))
}
}

View File

@@ -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()
) {

View File

@@ -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)

View File

@@ -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()
}
}

View File

@@ -93,7 +93,7 @@
<string name="max_pwd_fail_textfield">错误次数</string>
<string name="pwd_timeout">密码失效超时时间</string>
<string name="pwd_timeout_desc">超时后用户需重新设置密码毫秒0为无限制</string>
<string name="pwd_timeout_textfield">超时时间</string>
<string name="pwd_timeout_textfield">超时时间(ms)</string>
<string name="pwd_history">密码历史记录长度</string>
<string name="pwd_history_desc">用户输入的密码不能与历史记录中的任何密码相同0为无限制</string>
<string name="pwd_history_textfield">历史记录长度</string>
@@ -112,4 +112,7 @@
<string name="experimental_feature">实验性功能</string>
<string name="network_logging">网络日志记录</string>
<string name="no_effect">没啥用</string>
<string name="max_time_to_lock">屏幕超时</string>
<string name="max_time_to_lock_desc">超时后锁屏(毫秒)0为由用户决定</string>
<string name="max_time_to_lock_textfield">超时时间(ms)</string>
</resources>