diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/Password.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/Password.kt
index 8e453c0..b17f9e8 100644
--- a/app/src/main/java/com/bintianqi/owndroid/dpm/Password.kt
+++ b/app/src/main/java/com/bintianqi/owndroid/dpm/Password.kt
@@ -71,6 +71,7 @@ fun Password(navCtrl: NavHostController) {
composable(route = "MaxTimeToLock") { ScreenTimeout() }
composable(route = "PasswordTimeout") { PasswordExpiration() }
composable(route = "MaxPasswordFail") { MaxFailedPasswordForWipe() }
+ composable(route = "RequiredStrongAuthTimeout") { RequiredStrongAuthTimeout() }
composable(route = "PasswordHistoryLength") { PasswordHistoryLength() }
composable(route = "RequirePasswordQuality") { PasswordQuality() }
}
@@ -79,6 +80,8 @@ fun Password(navCtrl: NavHostController) {
@Composable
private fun Home(navCtrl:NavHostController,scrollState: ScrollState) {
+ val context = LocalContext.current
+ val dpm = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
Column(modifier = Modifier.fillMaxSize().verticalScroll(scrollState)) {
Text(
text = stringResource(R.string.password_and_keyguard),
@@ -94,10 +97,15 @@ private fun Home(navCtrl:NavHostController,scrollState: ScrollState) {
SubPageItem(R.string.required_password_complexity, "", R.drawable.password_fill0) { navCtrl.navigate("RequirePasswordComplexity") }
}
SubPageItem(R.string.keyguard_disabled_features, "", R.drawable.screen_lock_portrait_fill0) { navCtrl.navigate("KeyguardDisabledFeatures") }
- SubPageItem(R.string.max_time_to_lock, "", R.drawable.schedule_fill0) { navCtrl.navigate("MaxTimeToLock") }
- SubPageItem(R.string.pwd_timeout, "", R.drawable.lock_clock_fill0) { navCtrl.navigate("PasswordTimeout") }
- SubPageItem(R.string.max_pwd_fail, "", R.drawable.no_encryption_fill0) { navCtrl.navigate("MaxPasswordFail") }
- SubPageItem(R.string.pwd_history, "", R.drawable.history_fill0) { navCtrl.navigate("PasswordHistoryLength") }
+ if(isDeviceOwner(dpm)) {
+ SubPageItem(R.string.max_time_to_lock, "", R.drawable.schedule_fill0) { navCtrl.navigate("MaxTimeToLock") }
+ SubPageItem(R.string.pwd_timeout, "", R.drawable.lock_clock_fill0) { navCtrl.navigate("PasswordTimeout") }
+ SubPageItem(R.string.max_pwd_fail, "", R.drawable.no_encryption_fill0) { navCtrl.navigate("MaxPasswordFail") }
+ SubPageItem(R.string.pwd_history, "", R.drawable.history_fill0) { navCtrl.navigate("PasswordHistoryLength") }
+ }
+ if(VERSION.SDK_INT >= 26 && (isDeviceOwner(dpm) || isProfileOwner(dpm))) {
+ SubPageItem(R.string.required_strong_auth_timeout, "", R.drawable.fingerprint_off_fill0) { navCtrl.navigate("RequiredStrongAuthTimeout") }
+ }
SubPageItem(R.string.required_password_quality, "", R.drawable.password_fill0) { navCtrl.navigate("RequirePasswordQuality") }
Spacer(Modifier.padding(vertical = 30.dp))
}
@@ -349,8 +357,8 @@ private fun ScreenTimeout() {
val dpm = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
val receiver = ComponentName(context,Receiver::class.java)
val focusMgr = LocalFocusManager.current
- var inputContent by remember { mutableStateOf(if(isDeviceOwner(dpm)) dpm.getMaximumTimeToLock(receiver).toString() else "") }
- var ableToApply by remember { mutableStateOf(inputContent!="") }
+ 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)
@@ -360,33 +368,65 @@ private fun ScreenTimeout() {
OutlinedTextField(
value = inputContent,
label = { Text(stringResource(R.string.time_unit_ms)) },
- onValueChange = {
- inputContent = it
- ableToApply = inputContent != ""
- },
+ onValueChange = { inputContent = it },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
- enabled = isDeviceOwner(dpm),
modifier = Modifier.focusable().fillMaxWidth()
)
Spacer(Modifier.padding(vertical = 5.dp))
Button(
- onClick = { focusMgr.clearFocus(); dpm.setMaximumTimeToLock(receiver,inputContent.toLong()) },
- modifier = Modifier.fillMaxWidth()
+ 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.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
+ val receiver = ComponentName(context,Receiver::class.java)
+ 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.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
val receiver = ComponentName(context,Receiver::class.java)
val focusMgr = LocalFocusManager.current
- var inputContent by remember { mutableStateOf(if(isDeviceOwner(dpm)) dpm.getMaximumFailedPasswordsForWipe(receiver).toString() else "") }
- var ableToApply by remember { mutableStateOf(inputContent != "" && inputContent != "0") }
+ 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)
@@ -396,19 +436,16 @@ private fun MaxFailedPasswordForWipe() {
OutlinedTextField(
value = inputContent,
label = { Text(stringResource(R.string.max_pwd_fail_textfield)) },
- onValueChange = {
- inputContent = it
- ableToApply = inputContent != "" && inputContent != "0"
- },
+ onValueChange = { inputContent = it },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
- enabled = isDeviceOwner(dpm),
modifier = Modifier.focusable().fillMaxWidth()
)
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = { focusMgr.clearFocus(); dpm.setMaximumFailedPasswordsForWipe(receiver,inputContent.toInt()) },
- modifier = Modifier.fillMaxWidth()
+ modifier = Modifier.fillMaxWidth(),
+ enabled = inputContent != ""
) {
Text(stringResource(R.string.apply))
}
@@ -421,8 +458,8 @@ private fun PasswordExpiration() {
val dpm = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
val receiver = ComponentName(context,Receiver::class.java)
val focusMgr = LocalFocusManager.current
- var inputContent by remember { mutableStateOf(if(isDeviceOwner(dpm)) dpm.getPasswordExpirationTimeout(receiver).toString() else "") }
- var ableToApply by remember { mutableStateOf(inputContent != "") }
+ 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_timeout), style = typography.headlineLarge)
@@ -432,19 +469,16 @@ private fun PasswordExpiration() {
OutlinedTextField(
value = inputContent,
label = { Text(stringResource(R.string.time_unit_ms)) },
- onValueChange = {
- inputContent = it
- ableToApply = inputContent != ""
- },
+ onValueChange = { inputContent = it },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
- enabled = isDeviceOwner(dpm),
modifier = Modifier.focusable().fillMaxWidth()
)
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = { focusMgr.clearFocus() ; dpm.setPasswordExpirationTimeout(receiver,inputContent.toLong()) },
- modifier = Modifier.fillMaxWidth()
+ modifier = Modifier.fillMaxWidth(),
+ enabled = inputContent != ""
) {
Text(stringResource(R.string.apply))
}
@@ -457,8 +491,8 @@ private fun PasswordHistoryLength() {
val dpm = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
val receiver = ComponentName(context,Receiver::class.java)
val focusMgr = LocalFocusManager.current
- var inputContent by remember { mutableStateOf(if(isDeviceOwner(dpm)) dpm.getPasswordHistoryLength(receiver).toString() else "") }
- var ableToApply by remember { mutableStateOf(inputContent!="") }
+ 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)
@@ -468,19 +502,16 @@ private fun PasswordHistoryLength() {
OutlinedTextField(
value = inputContent,
label = { Text(stringResource(R.string.length)) },
- onValueChange = {
- inputContent = it
- ableToApply = inputContent != ""
- },
+ onValueChange = { inputContent = it },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
- enabled = isDeviceOwner(dpm),
modifier = Modifier.focusable().fillMaxWidth()
)
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = { focusMgr.clearFocus() ; dpm.setPasswordHistoryLength(receiver,inputContent.toInt()) },
- modifier = Modifier.fillMaxWidth()
+ modifier = Modifier.fillMaxWidth(),
+ enabled = inputContent != ""
) {
Text(stringResource(R.string.apply))
}
diff --git a/app/src/main/res/drawable/fingerprint_off_fill0.xml b/app/src/main/res/drawable/fingerprint_off_fill0.xml
new file mode 100644
index 0000000..67246ad
--- /dev/null
+++ b/app/src/main/res/drawable/fingerprint_off_fill0.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index b1e53be..fbfad0c 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -456,6 +456,8 @@
错误次数
密码失效超时时间
屏幕超时
+ 要求强验证超时
+ 值为0表示OwnDroid不参与控制超时
超时后锁屏(毫秒),0为由用户决定
超时后用户需重新设置密码(毫秒),0为无限制
密码历史记录长度
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index dceff34..46b9f71 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -472,6 +472,8 @@
Maximum failed attempts
Password timeout
Screen timeout
+ Required strong auth timeout
+ A value of 0 means the admin is not participating in controlling the timeout
Enter 0 to allow user decision, unit: millisecond
When reach this limit, user should set a new password. Enter 0 to allow user decision, unit: millisecond
Password history length