Add new features to the password section

This commit is contained in:
BinTianqi
2024-01-18 20:53:16 +08:00
parent 5aab260644
commit 13fa0d7b4d
4 changed files with 180 additions and 96 deletions

View File

@@ -86,7 +86,7 @@ fun MyScaffold(mainDpm:DevicePolicyManager, mainComponent:ComponentName, mainCon
"UIControl" to R.string.ui_ctrl, "UIControl" to R.string.ui_ctrl,
"ApplicationManage" to R.string.app_manage, "ApplicationManage" to R.string.app_manage,
"UserRestriction" to R.string.user_restrict, "UserRestriction" to R.string.user_restrict,
"Security" to R.string.security "Password" to R.string.password
) )
val topBarName = topBarNameMap[backStackEntry?.destination?.route]?: R.string.app_name val topBarName = topBarNameMap[backStackEntry?.destination?.route]?: R.string.app_name
Scaffold( Scaffold(
@@ -135,7 +135,7 @@ fun MyScaffold(mainDpm:DevicePolicyManager, mainComponent:ComponentName, mainCon
composable(route = "Permissions", content = { DpmPermissions(mainDpm,mainComponent,mainContext,navCtrl)}) composable(route = "Permissions", content = { DpmPermissions(mainDpm,mainComponent,mainContext,navCtrl)})
composable(route = "ApplicationManage", content = { ApplicationManage(mainDpm,mainComponent,mainContext)}) composable(route = "ApplicationManage", content = { ApplicationManage(mainDpm,mainComponent,mainContext)})
composable(route = "UserRestriction", content = { UserRestriction(mainDpm,mainComponent)}) composable(route = "UserRestriction", content = { UserRestriction(mainDpm,mainComponent)})
composable(route = "Security", content = { Security(mainDpm,mainComponent,mainContext)}) composable(route = "Password", content = { Password(mainDpm,mainComponent,mainContext)})
} }
} }
} }
@@ -181,7 +181,7 @@ fun HomePage(navCtrl:NavHostController,myDpm:DevicePolicyManager,myComponent:Com
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.app_manage, R.drawable.apps_fill0, R.string.apps_ctrl_description, "ApplicationManage", navCtrl) HomePageItem(R.string.app_manage, R.drawable.apps_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.manage_accounts_fill0, R.string.user_restrict_desc, "UserRestriction", navCtrl)
HomePageItem(R.string.security, R.drawable.security_fill0,R.string.security_desc, "Security",navCtrl) HomePageItem(R.string.password, R.drawable.password_fill0,R.string.security_desc, "Password",navCtrl)
} }
} }

View File

@@ -74,7 +74,7 @@ fun DpmPermissions(myDpm: DevicePolicyManager, myComponent: ComponentName, myCon
Text("撤销") Text("撤销")
} }
}else{ }else{
Button(onClick = { ActivateDeviceAdmin(myDpm, myComponent, myContext) }) { Button(onClick = { ActivateDeviceAdmin(myComponent, myContext) }) {
Text("激活") Text("激活")
} }
} }
@@ -141,7 +141,7 @@ fun DpmPermissions(myDpm: DevicePolicyManager, myComponent: ComponentName, myCon
} }
} }
fun ActivateDeviceAdmin(myDpm: DevicePolicyManager,myComponent: ComponentName,myContext: Context){ fun ActivateDeviceAdmin(myComponent: ComponentName,myContext: Context){
val intent = Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN) val intent = Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN)
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, myComponent) intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, myComponent)
intent.putExtra( intent.putExtra(

View File

@@ -7,15 +7,24 @@ import android.content.Context
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.os.Build.VERSION import android.os.Build.VERSION
import android.widget.Toast import android.widget.Toast
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
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.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Check
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextField import androidx.compose.material3.TextField
@@ -27,40 +36,52 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment 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.focus.FocusManager
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat.startActivity import androidx.core.content.ContextCompat.startActivity
@Composable @Composable
fun Security(myDpm:DevicePolicyManager,myComponent:ComponentName,myContext:Context){ fun Password(myDpm:DevicePolicyManager,myComponent:ComponentName,myContext:Context){
var newPwd by remember{ mutableStateOf("") } var newPwd by remember{ mutableStateOf("") }
var confirmed by remember{ mutableStateOf(false) } var confirmed by remember{ mutableStateOf(false) }
val focusMgr = LocalFocusManager.current
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth() modifier = Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState())
) { ) {
val myByteArray by remember{ mutableStateOf(byteArrayOf(1,1,4,5,1,4,1,9,1,9,8,1,0,1,1,4,5,1,4,1,9,1,9,8,1,0,1,1,4,5,1,4,1,9,1,9,8,1,0)) } val myByteArray by remember{ mutableStateOf(byteArrayOf(1,1,4,5,1,4,1,9,1,9,8,1,0,1,1,4,5,1,4,1,9,1,9,8,1,0,1,1,4,5,1,4,1,9,1,9,8,1,0)) }
Text(
text = "以下操作可能会造成不可挽回的损失,请先备份好数据。执行操作时一定要谨慎!!!",
color = MaterialTheme.colorScheme.onErrorContainer,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 8.dp, vertical = 4.dp)
.clip(RoundedCornerShape(15))
.background(color = MaterialTheme.colorScheme.errorContainer)
.padding(8.dp)
)
if(VERSION.SDK_INT>=26){ if(VERSION.SDK_INT>=26){
Column( Column(
horizontalAlignment = Alignment.Start, horizontalAlignment = Alignment.Start,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(8.dp) .padding(horizontal = 8.dp, vertical = 4.dp)
.clip(RoundedCornerShape(10)) .clip(RoundedCornerShape(10))
.background(color = MaterialTheme.colorScheme.primaryContainer) .background(color = MaterialTheme.colorScheme.primaryContainer)
.padding(8.dp) .padding(8.dp)
) { ) {
Text( Text(text = "密码重置令牌", style = MaterialTheme.typography.titleLarge)
text = "密码重置令牌",
style = MaterialTheme.typography.titleLarge
)
Row { Row {
Button( Button(
onClick = { onClick = {
if(myDpm.clearResetPasswordToken(myComponent)){ if(myDpm.clearResetPasswordToken(myComponent)){ Toast.makeText(myContext, "清除成功", Toast.LENGTH_SHORT).show()
Toast.makeText(myContext, "清除成功", Toast.LENGTH_SHORT).show() }else{ Toast.makeText(myContext, "清除失败", Toast.LENGTH_SHORT).show() }
}else{
Toast.makeText(myContext, "清除失败", Toast.LENGTH_SHORT).show()
}
}, },
modifier = Modifier.padding(end = 8.dp) modifier = Modifier.padding(end = 8.dp)
) { ) {
@@ -68,11 +89,8 @@ fun Security(myDpm:DevicePolicyManager,myComponent:ComponentName,myContext:Conte
} }
Button( Button(
onClick = { onClick = {
if(myDpm.setResetPasswordToken(myComponent, myByteArray)){ if(myDpm.setResetPasswordToken(myComponent, myByteArray)){ Toast.makeText(myContext, "设置成功", Toast.LENGTH_SHORT).show()
Toast.makeText(myContext, "设置成功", Toast.LENGTH_SHORT).show() }else{ Toast.makeText(myContext, "设置失败", Toast.LENGTH_SHORT).show() }
}else{
Toast.makeText(myContext, "设置失败", Toast.LENGTH_SHORT).show()
}
}, },
modifier = Modifier.padding(end = 8.dp) modifier = Modifier.padding(end = 8.dp)
) { ) {
@@ -81,14 +99,9 @@ fun Security(myDpm:DevicePolicyManager,myComponent:ComponentName,myContext:Conte
Button( Button(
onClick = { onClick = {
if(!myDpm.isResetPasswordTokenActive(myComponent)){ if(!myDpm.isResetPasswordTokenActive(myComponent)){
try{ try{ activateToken(myContext)
activateToken(myContext) }catch(e:NullPointerException){ Toast.makeText(myContext, "请先设置令牌", Toast.LENGTH_SHORT).show() }
}catch(e:NullPointerException){ }else{ Toast.makeText(myContext, "已经激活", Toast.LENGTH_SHORT).show() }
Toast.makeText(myContext, "请先设置令牌", Toast.LENGTH_SHORT).show()
}
}else{
Toast.makeText(myContext, "已经激活", Toast.LENGTH_SHORT).show()
}
} }
) { ) {
Text("激活") Text("激活")
@@ -97,83 +110,144 @@ fun Security(myDpm:DevicePolicyManager,myComponent:ComponentName,myContext:Conte
Text("没有密码时会自动激活令牌") Text("没有密码时会自动激活令牌")
} }
} }
TextField( Column(
value = newPwd, modifier = Modifier
onValueChange = {newPwd=it}, .fillMaxWidth()
enabled = !confirmed, .padding(horizontal = 8.dp, vertical = 4.dp)
label = { Text("密码")} .clip(RoundedCornerShape(10))
) .background(color = MaterialTheme.colorScheme.primaryContainer)
Text( .padding(10.dp)
text = "(留空可以清除密码)", ) {
modifier = Modifier.padding(vertical = 5.dp) TextField(
) value = newPwd,
Row { onValueChange = {newPwd=it},
Button( enabled = !confirmed,
onClick = { label = { Text("密码")},
if(newPwd.length>=4||newPwd.isEmpty()){ keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password, imeAction = ImeAction.Done),
confirmed=!confirmed keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()})
}else{ )
Toast.makeText(myContext, "需要4位数字或字母", Toast.LENGTH_SHORT).show() Text(text = stringResource(R.string.reset_pwd_desc), modifier = Modifier.padding(vertical = 5.dp))
} Row {
},
modifier = Modifier.padding(end = 10.dp)
) {
Text("确认密码")
}
if(VERSION.SDK_INT>=26){
Button( Button(
onClick = { onClick = {
val resetSuccess = myDpm.resetPasswordWithToken(myComponent,newPwd,myByteArray,0) if(newPwd.length>=4||newPwd.isEmpty()){ confirmed=!confirmed
if(resetSuccess){ }else{ Toast.makeText(myContext, "需要4位数字或字母", Toast.LENGTH_SHORT).show() }
Toast.makeText(myContext, "设置成功", Toast.LENGTH_SHORT).show()
}else{
Toast.makeText(myContext, "设置失败", Toast.LENGTH_SHORT).show()
}
confirmed=false
}, },
enabled = confirmed, modifier = Modifier.padding(end = 10.dp)
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.error,
contentColor = MaterialTheme.colorScheme.onError
)
) { ) {
Text("设置密码") Text("确认密码")
} }
}else{ if(VERSION.SDK_INT>=26){
Button( Button(
onClick = { onClick = {
val resetSuccess = myDpm.resetPassword(newPwd,0) val resetSuccess = myDpm.resetPasswordWithToken(myComponent,newPwd,myByteArray,0)
if(resetSuccess){ if(resetSuccess){ Toast.makeText(myContext, "设置成功", Toast.LENGTH_SHORT).show()
Toast.makeText(myContext, "设置成功", Toast.LENGTH_SHORT).show() }else{ Toast.makeText(myContext, "设置失败", Toast.LENGTH_SHORT).show() }
}else{ confirmed=false
Toast.makeText(myContext, "设置失败", Toast.LENGTH_SHORT).show() },
} enabled = confirmed,
confirmed=false colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.error, contentColor = MaterialTheme.colorScheme.onError)
}, ) {
colors = ButtonDefaults.buttonColors( Text("设置密码")
containerColor = MaterialTheme.colorScheme.error, }
contentColor = MaterialTheme.colorScheme.onError }else{
) Button(
) { onClick = {
Text("设置密码") val resetSuccess = myDpm.resetPassword(newPwd,0)
if(resetSuccess){ Toast.makeText(myContext, "设置成功", Toast.LENGTH_SHORT).show()
}else{ Toast.makeText(myContext, "设置失败", Toast.LENGTH_SHORT).show() }
confirmed=false
},
colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.error, contentColor = MaterialTheme.colorScheme.onError)
) {
Text("设置密码")
}
} }
} }
} }
Text( PasswordItem(R.string.max_pwd_fail,R.string.max_pwd_fail_desc,R.string.max_pwd_fail_textfield, focusMgr,false,
text = "该操作可能会造成不可挽回的损失,请先备份好数据。设置密码的时候一定要谨慎!!!", {myDpm.getMaximumFailedPasswordsForWipe(null).toString()},{ic -> myDpm.setMaximumFailedPasswordsForWipe(myComponent, ic.toInt()) })
color = MaterialTheme.colorScheme.onErrorContainer, PasswordItem(R.string.pwd_timeout,R.string.pwd_timeout_desc,R.string.pwd_timeout_textfield, focusMgr,true,
{myDpm.getPasswordExpirationTimeout(null).toString()},{ic -> myDpm.setPasswordExpirationTimeout(myComponent, ic.toLong()) })
PasswordItem(R.string.pwd_history,R.string.pwd_history_desc,R.string.pwd_history_textfield, focusMgr,true,
{myDpm.getPasswordHistoryLength(null).toString()},{ic -> myDpm.setPasswordHistoryLength(myComponent, ic.toInt()) })
}
}
@Composable
fun PasswordItem(
itemName:Int,
itemDesc:Int,
textFieldLabel:Int,
focusMgr:FocusManager,
allowZero:Boolean,
getMethod:()->String,
setMethod:(ic:String)->Unit
){
Column(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 8.dp, vertical = 4.dp)
.clip(RoundedCornerShape(10))
.background(color = MaterialTheme.colorScheme.primaryContainer)
.padding(10.dp)
) {
var inputContent by remember{ mutableStateOf(getMethod()) }
var inputContentEdited by remember{ mutableStateOf(false) }
var ableToApply by remember{ mutableStateOf(true) }
Text(text = stringResource(itemName), style = MaterialTheme.typography.titleLarge)
Text(text= stringResource(itemDesc),modifier=Modifier.padding(vertical = 2.dp))
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(8.dp) .padding(end = 8.dp)
.clip(RoundedCornerShape(15)) ){
.background(color = MaterialTheme.colorScheme.errorContainer) TextField(
.padding(8.dp) value = inputContent,
) label = { Text(stringResource(textFieldLabel))},
onValueChange = {
inputContent = it
if(inputContent!=""&&((inputContent=="0"&&allowZero)||inputContent!="0")){
inputContentEdited = inputContent!=getMethod()
ableToApply = true
}else{
ableToApply = false
}
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()})
)
if(ableToApply){
Icon(
imageVector = Icons.Outlined.Check,
contentDescription = null,
tint = if(inputContentEdited){MaterialTheme.colorScheme.onError}else{MaterialTheme.colorScheme.onPrimary},
modifier = Modifier
.clip(RoundedCornerShape(20))
.background(
color = if (inputContentEdited) {
MaterialTheme.colorScheme.error
} else {
MaterialTheme.colorScheme.primary
}
)
.clickable(onClick = {
focusMgr.clearFocus()
setMethod(inputContent)
inputContentEdited = inputContent != getMethod()
})
.padding(8.dp)
)
}
}
} }
} }
fun activateToken(myContext: Context){ fun activateToken(myContext: Context){
val ACTIVATE_TOKEN_PROMPT = "Use your credentials to enable remote password reset" val ACTIVATE_TOKEN_PROMPT = "在这里激活密码重置令牌"
val keyguardManager = myContext.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager val keyguardManager = myContext.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
val confirmIntent = keyguardManager.createConfirmDeviceCredentialIntent(null, ACTIVATE_TOKEN_PROMPT) val confirmIntent = keyguardManager.createConfirmDeviceCredentialIntent(null, ACTIVATE_TOKEN_PROMPT)
confirmIntent.setFlags(FLAG_ACTIVITY_NEW_TASK) confirmIntent.setFlags(FLAG_ACTIVITY_NEW_TASK)

View File

@@ -47,7 +47,17 @@
<string name="sometimes_not_available">有时候不能用</string> <string name="sometimes_not_available">有时候不能用</string>
<string name="user_ctrl_disabled">禁止用户控制</string> <string name="user_ctrl_disabled">禁止用户控制</string>
<string name="user_ctrl_disabled_desc">阻止清除应用数据和缓存</string> <string name="user_ctrl_disabled_desc">阻止清除应用数据和缓存</string>
<string name="security">安全</string> <string name="password">密码</string>
<string name="inst_unknown_src">安装未知来源应用</string> <string name="inst_unknown_src">安装未知来源应用</string>
<string name="security_desc">修改或清除锁屏密码</string>> <string name="security_desc">锁屏密码相关操作</string>
<string name="max_pwd_fail">最大密码错误次数</string>
<string name="max_pwd_fail_desc">达到该限制会恢复出厂设置</string>
<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_history">密码历史记录长度</string>
<string name="pwd_history_desc">用户输入的密码不能与历史记录中的任何密码相同0为无限制</string>
<string name="pwd_history_textfield">历史记录长度</string>
<string name="reset_pwd_desc">留空可以清除密码纯数字将使用PIN码</string>
</resources> </resources>