Use dialog to set some password options

This commit is contained in:
BinTianqi
2024-10-19 12:39:52 +08:00
parent 36609d68ef
commit 951231abe3
7 changed files with 122 additions and 196 deletions

View File

@@ -39,8 +39,8 @@ fun uriToStream(
if(stream != null) { operation(stream) }
stream?.close()
}
catch(e: FileNotFoundException) { Toast.makeText(context, R.string.file_not_exist, Toast.LENGTH_SHORT).show() }
catch(e: IOException) { Toast.makeText(context, R.string.io_exception, Toast.LENGTH_SHORT).show() }
catch(_: FileNotFoundException) { Toast.makeText(context, R.string.file_not_exist, Toast.LENGTH_SHORT).show() }
catch(_: IOException) { Toast.makeText(context, R.string.io_exception, Toast.LENGTH_SHORT).show() }
}
}
@@ -52,7 +52,7 @@ fun writeClipBoard(context: Context, string: String):Boolean{
val clipboardManager = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
try {
clipboardManager.setPrimaryClip(ClipData.newPlainText("", string))
}catch(e:Exception){
} catch(_:Exception) {
return false
}
return true

View File

@@ -118,16 +118,12 @@ fun Password(navCtrl: NavHostController) {
composable(route = "ResetPassword") { ResetPassword() }
composable(route = "RequirePasswordComplexity") { PasswordComplexity() }
composable(route = "DisableKeyguardFeatures") { DisableKeyguardFeatures() }
composable(route = "MaxTimeToLock") { ScreenTimeout() }
composable(route = "PasswordTimeout") { PasswordExpiration() }
composable(route = "MaxPasswordFail") { MaxFailedPasswordForWipe() }
composable(route = "RequiredStrongAuthTimeout") { RequiredStrongAuthTimeout() }
composable(route = "PasswordHistoryLength") { PasswordHistoryLength() }
composable(route = "RequirePasswordQuality") { PasswordQuality() }
}
}
}
@SuppressLint("NewApi")
@Composable
private fun Home(navCtrl:NavHostController, scrollState: ScrollState) {
val context = LocalContext.current
@@ -135,6 +131,7 @@ private fun Home(navCtrl:NavHostController, scrollState: ScrollState) {
val deviceAdmin = context.isDeviceAdmin
val deviceOwner = context.isDeviceOwner
val profileOwner = context.isProfileOwner
var dialog by remember { mutableIntStateOf(0) }
Column(modifier = Modifier.fillMaxSize().verticalScroll(scrollState)) {
Text(
text = stringResource(R.string.password_and_keyguard),
@@ -157,21 +154,101 @@ private fun Home(navCtrl:NavHostController, scrollState: ScrollState) {
SubPageItem(R.string.disable_keyguard_features, "", R.drawable.screen_lock_portrait_fill0) { navCtrl.navigate("DisableKeyguardFeatures") }
}
if(deviceOwner) {
SubPageItem(R.string.max_time_to_lock, "", R.drawable.schedule_fill0) { navCtrl.navigate("MaxTimeToLock") }
SubPageItem(R.string.pwd_expiration_timeout, "", R.drawable.lock_clock_fill0) { navCtrl.navigate("PasswordTimeout") }
SubPageItem(R.string.max_pwd_fail, "", R.drawable.no_encryption_fill0) { navCtrl.navigate("MaxPasswordFail") }
}
if(deviceAdmin){
SubPageItem(R.string.pwd_history, "", R.drawable.history_fill0) { navCtrl.navigate("PasswordHistoryLength") }
SubPageItem(R.string.max_time_to_lock, "", R.drawable.schedule_fill0) { dialog = 1 }
SubPageItem(R.string.pwd_expiration_timeout, "", R.drawable.lock_clock_fill0) { dialog = 3 }
SubPageItem(R.string.max_pwd_fail, "", R.drawable.no_encryption_fill0) { dialog = 4 }
}
if(VERSION.SDK_INT >= 26 && (deviceOwner || profileOwner)) {
SubPageItem(R.string.required_strong_auth_timeout, "", R.drawable.fingerprint_off_fill0) { navCtrl.navigate("RequiredStrongAuthTimeout") }
SubPageItem(R.string.required_strong_auth_timeout, "", R.drawable.fingerprint_off_fill0) { dialog = 2 }
}
if(deviceAdmin){
SubPageItem(R.string.pwd_history, "", R.drawable.history_fill0) { dialog = 5 }
}
if(VERSION.SDK_INT < 31 && (deviceOwner || profileOwner)) {
SubPageItem(R.string.required_password_quality, "", R.drawable.password_fill0) { navCtrl.navigate("RequirePasswordQuality") }
}
Spacer(Modifier.padding(vertical = 30.dp))
}
if(dialog != 0) {
val dpm = context.getDPM()
val receiver = context.getReceiver()
var input by remember { mutableStateOf("") }
LaunchedEffect(Unit) {
input = when(dialog) {
1 -> dpm.getMaximumTimeToLock(receiver).toString()
2 -> dpm.getRequiredStrongAuthTimeout(receiver).toString()
3 -> dpm.getPasswordExpirationTimeout(receiver).toString()
4 -> dpm.getMaximumFailedPasswordsForWipe(receiver).toString()
5 -> dpm.getPasswordHistoryLength(receiver).toString()
else -> ""
}
}
AlertDialog(
title = {
Text(stringResource(
when(dialog) {
1 -> R.string.max_time_to_lock
2 -> R.string.required_strong_auth_timeout
3 -> R.string.pwd_expiration_timeout
4 -> R.string.max_pwd_fail
5 -> R.string.pwd_history
else -> R.string.password
}
))
},
text = {
val focusMgr = LocalFocusManager.current
Column {
OutlinedTextField(
value = input,
label = {
Text(stringResource(
when(dialog) {
1,2,3 -> R.string.time_unit_ms
4 -> R.string.max_pwd_fail_textfield
5 -> R.string.length
else -> R.string.password
}
))
},
onValueChange = { input = it },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
modifier = Modifier.fillMaxWidth().padding(bottom = 5.dp)
)
when(dialog) {
4 -> Text(stringResource(R.string.max_pwd_fail_desc))
5 -> Text(stringResource(R.string.pwd_history_desc))
}
Text(stringResource(R.string.zero_means_no_restriction))
}
},
confirmButton = {
TextButton(
onClick = {
when(dialog) {
1 -> dpm.setMaximumTimeToLock(receiver, input.toLong())
2 -> dpm.setRequiredStrongAuthTimeout(receiver, input.toLong())
3 -> dpm.setPasswordExpirationTimeout(receiver, input.toLong())
4 -> dpm.setMaximumFailedPasswordsForWipe(receiver, input.toInt())
5 -> dpm.setPasswordHistoryLength(receiver, input.toInt())
}
dialog = 0
}
) {
Text(stringResource(R.string.apply))
}
},
dismissButton = {
TextButton(onClick = { dialog = 0 }) {
Text(stringResource(R.string.cancel))
}
},
onDismissRequest = {
dialog = 0
}
)
}
}
@Composable
@@ -242,7 +319,7 @@ private fun ResetPasswordToken() {
if(dpm.setResetPasswordToken(receiver, tokenByteArray)) R.string.success else R.string.failed,
Toast.LENGTH_SHORT
).show()
}catch(e:SecurityException) {
}catch(_:SecurityException) {
Toast.makeText(context, R.string.security_exception, Toast.LENGTH_SHORT).show()
}
},
@@ -259,7 +336,7 @@ private fun ResetPasswordToken() {
onClick = {
if(!dpm.isResetPasswordTokenActive(receiver)) {
try { activateToken(context) }
catch(e:NullPointerException) { Toast.makeText(context, R.string.please_set_a_token, Toast.LENGTH_SHORT).show() }
catch(_:NullPointerException) { Toast.makeText(context, R.string.please_set_a_token, Toast.LENGTH_SHORT).show() }
} else { Toast.makeText(context, R.string.token_already_activated, Toast.LENGTH_SHORT).show() }
},
modifier = Modifier.fillMaxWidth(0.49F)
@@ -454,175 +531,6 @@ private fun PasswordComplexity() {
}
}
@Composable
private fun ScreenTimeout() {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
var inputContent by remember { mutableStateOf("") }
LaunchedEffect(Unit) { inputContent = dpm.getMaximumTimeToLock(receiver).toString() }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.max_time_to_lock), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
Text(text= stringResource(R.string.max_time_to_lock_desc),modifier=Modifier.padding(vertical = 2.dp))
Spacer(Modifier.padding(vertical = 5.dp))
OutlinedTextField(
value = inputContent,
label = { Text(stringResource(R.string.time_unit_ms)) },
onValueChange = { inputContent = it },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
modifier = Modifier.fillMaxWidth()
)
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = { focusMgr.clearFocus(); dpm.setMaximumTimeToLock(receiver, inputContent.toLong()) },
modifier = Modifier.fillMaxWidth(),
enabled = inputContent != ""
) {
Text(stringResource(R.string.apply))
}
}
}
@SuppressLint("NewApi")
@Composable
private fun RequiredStrongAuthTimeout() {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
var input by remember { mutableStateOf("") }
LaunchedEffect(Unit) { input = dpm.getRequiredStrongAuthTimeout(receiver).toString() }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.required_strong_auth_timeout), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
OutlinedTextField(
value = input,
label = { Text(stringResource(R.string.time_unit_ms)) },
onValueChange = { input = it },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
modifier = Modifier.fillMaxWidth()
)
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = { focusMgr.clearFocus(); dpm.setRequiredStrongAuthTimeout(receiver, input.toLong()) },
modifier = Modifier.fillMaxWidth(),
enabled = input != ""
) {
Text(stringResource(R.string.apply))
}
Spacer(Modifier.padding(vertical = 10.dp))
Information { Text(stringResource(R.string.zero_means_no_control)) }
Spacer(Modifier.padding(vertical = 60.dp))
}
}
@Composable
private fun MaxFailedPasswordForWipe() {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
var inputContent by remember { mutableStateOf("") }
LaunchedEffect(Unit) { inputContent = dpm.getMaximumFailedPasswordsForWipe(receiver).toString() }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.max_pwd_fail), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
Text(text= stringResource(R.string.max_pwd_fail_desc))
Spacer(Modifier.padding(vertical = 5.dp))
OutlinedTextField(
value = inputContent,
label = { Text(stringResource(R.string.max_pwd_fail_textfield)) },
onValueChange = { inputContent = it },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
modifier = Modifier.fillMaxWidth()
)
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = {
focusMgr.clearFocus()
dpm.setMaximumFailedPasswordsForWipe(receiver, inputContent.toInt())
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
},
modifier = Modifier.fillMaxWidth(),
enabled = inputContent != ""
) {
Text(stringResource(R.string.apply))
}
}
}
@Composable
private fun PasswordExpiration() {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
var inputContent by remember { mutableStateOf("") }
LaunchedEffect(Unit) { inputContent = dpm.getPasswordExpirationTimeout(receiver).toString() }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.pwd_expiration_timeout), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
OutlinedTextField(
value = inputContent,
label = { Text(stringResource(R.string.time_unit_ms)) },
onValueChange = { inputContent = it },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
modifier = Modifier.fillMaxWidth()
)
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = { focusMgr.clearFocus() ; dpm.setPasswordExpirationTimeout(receiver,inputContent.toLong()) },
modifier = Modifier.fillMaxWidth(),
enabled = inputContent != ""
) {
Text(stringResource(R.string.apply))
}
}
}
@Composable
private fun PasswordHistoryLength() {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
var inputContent by remember { mutableStateOf("") }
LaunchedEffect(Unit) { inputContent = dpm.getPasswordHistoryLength(receiver).toString() }
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.pwd_history), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
Text(text= stringResource(R.string.pwd_history_desc))
Spacer(Modifier.padding(vertical = 5.dp))
OutlinedTextField(
value = inputContent,
label = { Text(stringResource(R.string.length)) },
onValueChange = { inputContent = it },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
modifier = Modifier.fillMaxWidth()
)
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = { focusMgr.clearFocus() ; dpm.setPasswordHistoryLength(receiver,inputContent.toInt()) },
modifier = Modifier.fillMaxWidth(),
enabled = inputContent != ""
) {
Text(stringResource(R.string.apply))
}
}
}
@Composable
private fun DisableKeyguardFeatures() {
val context = LocalContext.current

View File

@@ -26,6 +26,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -49,7 +50,7 @@ fun ShizukuActivate() {
val outputTextScrollState = rememberScrollState()
var enabled by remember { mutableStateOf(false) }
var bindShizuku by remember { mutableStateOf(false) }
var outputText by remember { mutableStateOf("") }
var outputText by rememberSaveable { mutableStateOf("") }
var showDeviceAdminButton by remember { mutableStateOf(!context.isDeviceAdmin) }
var showDeviceOwnerButton by remember { mutableStateOf(!context.isDeviceOwner) }
var showOrgProfileOwnerButton by remember { mutableStateOf(true) }

View File

@@ -69,6 +69,7 @@ import com.bintianqi.owndroid.toggle
import com.bintianqi.owndroid.ui.Animations
import com.bintianqi.owndroid.ui.CheckBoxItem
import com.bintianqi.owndroid.ui.SubPageItem
import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.ui.TopBar
import com.bintianqi.owndroid.uriToStream
@@ -99,6 +100,7 @@ fun UserManage(navCtrl: NavHostController) {
) {
composable(route = "Home") { Home(localNavCtrl, scrollState) }
composable(route = "UserInfo") { CurrentUserInfo() }
composable(route = "Options") { Options() }
composable(route = "UserOperation") { UserOperation() }
composable(route = "CreateUser") { CreateUser() }
composable(route = "EditUsername") { Username() }
@@ -121,6 +123,9 @@ private fun Home(navCtrl: NavHostController,scrollState: ScrollState) {
modifier = Modifier.padding(top = 8.dp, bottom = 5.dp, start = 16.dp)
)
SubPageItem(R.string.user_info, "", R.drawable.person_fill0) { navCtrl.navigate("UserInfo") }
if(deviceOwner && VERSION.SDK_INT >= 28) {
SubPageItem(R.string.options, "", R.drawable.tune_fill0) { navCtrl.navigate("Options") }
}
if(deviceOwner) {
SubPageItem(R.string.user_operation, "", R.drawable.sync_alt_fill0) { navCtrl.navigate("UserOperation") }
}
@@ -144,6 +149,18 @@ private fun Home(navCtrl: NavHostController,scrollState: ScrollState) {
}
}
@Composable
private fun Options() {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState())) {
if(VERSION.SDK_INT >= 28) {
SwitchItem(R.string.enable_logout, "", null, { dpm.isLogoutEnabled }, { dpm.setLogoutEnabled(receiver, it) })
}
}
}
@Composable
private fun CurrentUserInfo() {
val context = LocalContext.current

View File

@@ -435,6 +435,7 @@
<!--UserManage-->
<string name="user_manager">Kullanıcı yöneticisi</string>
<string name="enable_logout">Enable logout</string> <!--TODO-->
<string name="edit_username">Kullanıcı adını düzenle</string>
<string name="start_user_session_msg">Kullanıcı oturumunu başlat mesajı</string>
<string name="end_user_session_msg">Kullanıcı oturumunu sonlandır mesajı</string>
@@ -483,8 +484,7 @@
<string name="pwd_expiration_timeout">Şifre geçerlilik süresi</string>
<string name="max_time_to_lock">Ekran zaman aşımı</string>
<string name="required_strong_auth_timeout">Gereken güçlü doğrulama zaman aşımı</string>
<string name="zero_means_no_control">0 değeri, yöneticinin zaman aşımını kontrol etmediği anlamına gelir</string>
<string name="max_time_to_lock_desc">Kullanıcı kararına izin vermek için 0 girin, birim: milisaniye</string>
<string name="zero_means_no_restriction">0 means no restriction</string> <!--TODO-->
<string name="pwd_history">Şifre geçmişi uzunluğu</string>
<string name="pwd_history_desc">Belirtilen aralıktaki geçmiş şifreler kullanıcı tarafından ayarlanamaz</string>
<string name="password_complexity_none">Yok (Şifreye izin verilmez)</string>

View File

@@ -29,7 +29,7 @@
<string name="custom">自定义</string>
<string name="unknown">未知</string>
<string name="reset">重置</string>
<string name="time_unit_ms">时间(ms)</string>
<string name="time_unit_ms">时间(毫秒)</string>
<string name="length">长度</string>
<string name="none"></string>
<string name="no_logs">无日志</string>
@@ -427,6 +427,7 @@
<!--UserManage-->
<string name="user_manager">用户管理</string>
<string name="enable_logout">允许登出</string>
<string name="edit_username">修改用户名</string>
<string name="start_user_session_msg">用户会话开始消息</string>
<string name="end_user_session_msg">用户会话结束消息</string>
@@ -470,13 +471,12 @@
<string name="password_info">密码信息</string>
<string name="reset_pwd_desc">留空以清除密码</string>
<string name="max_pwd_fail">最大密码错误次数</string>
<string name="max_pwd_fail_desc">达到该限制会恢复出厂设置0为无限制</string>
<string name="max_pwd_fail_desc">达到该限制会恢复出厂设置</string>
<string name="max_pwd_fail_textfield">错误次数</string>
<string name="pwd_expiration_timeout">密码失效超时时间</string>
<string name="pwd_expiration_timeout">密码失效超时</string>
<string name="max_time_to_lock">屏幕超时</string>
<string name="required_strong_auth_timeout">要求强验证超时</string>
<string name="zero_means_no_control">值为0表示OwnDroid不参与控制超时</string>
<string name="max_time_to_lock_desc">超时后锁屏(毫秒)0为由用户决定</string>
<string name="zero_means_no_restriction">0表示不做限制</string>
<string name="pwd_history">密码历史长度</string>
<string name="pwd_history_desc">用户无法设置指定历史范围内之前曾设置过的密码</string>
<string name="password_complexity_none">无(允许不设密码)</string>

View File

@@ -440,6 +440,7 @@
<!--UserManage-->
<string name="user_manager">User manager</string>
<string name="enable_logout">Enable logout</string>
<string name="edit_username">Edit username</string>
<string name="start_user_session_msg">Start user session message</string>
<string name="end_user_session_msg">End user session message</string>
@@ -488,8 +489,7 @@
<string name="pwd_expiration_timeout">Password expiration timeout</string>
<string name="max_time_to_lock">Screen timeout</string>
<string name="required_strong_auth_timeout">Required strong auth timeout</string>
<string name="zero_means_no_control">A value of 0 means the admin is not participating in controlling the timeout</string>
<string name="max_time_to_lock_desc">Enter 0 to allow user decision, unit: millisecond</string>
<string name="zero_means_no_restriction">0 means no restriction</string>
<string name="pwd_history">Password history length</string>
<string name="pwd_history_desc">Historical passwords within the specified range cannot be set by user</string>
<string name="password_complexity_none">None (No password allowed)</string>