mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-23 19:15:58 +00:00
Add delegated admin in a new screen
Some UI improvements Info of password complexity
This commit is contained in:
@@ -62,6 +62,8 @@ import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.toRoute
|
||||
import com.bintianqi.owndroid.dpm.Accounts
|
||||
import com.bintianqi.owndroid.dpm.AccountsScreen
|
||||
import com.bintianqi.owndroid.dpm.AddDelegatedAdmin
|
||||
import com.bintianqi.owndroid.dpm.AddDelegatedAdminScreen
|
||||
import com.bintianqi.owndroid.dpm.AddNetwork
|
||||
import com.bintianqi.owndroid.dpm.AddNetworkScreen
|
||||
import com.bintianqi.owndroid.dpm.AffiliationId
|
||||
@@ -167,7 +169,7 @@ import com.bintianqi.owndroid.dpm.SystemManager
|
||||
import com.bintianqi.owndroid.dpm.SystemManagerScreen
|
||||
import com.bintianqi.owndroid.dpm.SystemOptions
|
||||
import com.bintianqi.owndroid.dpm.SystemOptionsScreen
|
||||
import com.bintianqi.owndroid.dpm.SystemUpdatePolicy
|
||||
import com.bintianqi.owndroid.dpm.SystemUpdatePolicyScreen
|
||||
import com.bintianqi.owndroid.dpm.TransferOwnership
|
||||
import com.bintianqi.owndroid.dpm.TransferOwnershipScreen
|
||||
import com.bintianqi.owndroid.dpm.UserInfo
|
||||
@@ -264,6 +266,7 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) {
|
||||
}
|
||||
val userRestrictions by vm.userRestrictions.collectAsStateWithLifecycle()
|
||||
fun navigateUp() { navController.navigateUp() }
|
||||
fun navigate(destination: Any) { navController.navigate(destination) }
|
||||
@Suppress("NewApi") NavHost(
|
||||
navController = navController,
|
||||
startDestination = Home,
|
||||
@@ -290,13 +293,14 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) {
|
||||
composable<DeviceAdmin> { DeviceAdminScreen(::navigateUp) }
|
||||
composable<ProfileOwner> { ProfileOwnerScreen(::navigateUp) }
|
||||
composable<DeviceOwner> { DeviceOwnerScreen(::navigateUp) }
|
||||
composable<DelegatedAdmins> { DelegatedAdminsScreen(::navigateUp) }
|
||||
composable<DelegatedAdmins> { DelegatedAdminsScreen(::navigateUp, ::navigate) }
|
||||
composable<AddDelegatedAdmin>{ AddDelegatedAdminScreen(it.toRoute(), ::navigateUp) }
|
||||
composable<DeviceInfo> { DeviceInfoScreen(::navigateUp) }
|
||||
composable<LockScreenInfo> { LockScreenInfoScreen(::navigateUp) }
|
||||
composable<SupportMessage> { SupportMessageScreen(::navigateUp) }
|
||||
composable<TransferOwnership> { TransferOwnershipScreen(::navigateUp) }
|
||||
|
||||
composable<SystemManager> { SystemManagerScreen(::navigateUp) { navController.navigate(it) } }
|
||||
composable<SystemManager> { SystemManagerScreen(::navigateUp, ::navigate) }
|
||||
composable<SystemOptions> { SystemOptionsScreen(::navigateUp) }
|
||||
composable<Keyguard> { KeyguardScreen(::navigateUp) }
|
||||
composable<HardwareMonitor> { HardwareMonitorScreen(::navigateUp) }
|
||||
@@ -311,12 +315,12 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) {
|
||||
composable<CaCert> { CaCertScreen(::navigateUp) }
|
||||
composable<SecurityLogging> { SecurityLoggingScreen(::navigateUp) }
|
||||
composable<DisableAccountManagement> { DisableAccountManagementScreen(::navigateUp) }
|
||||
composable<SetSystemUpdatePolicy> { SystemUpdatePolicy(::navigateUp) }
|
||||
composable<SetSystemUpdatePolicy> { SystemUpdatePolicyScreen(::navigateUp) }
|
||||
composable<InstallSystemUpdate> { InstallSystemUpdateScreen(::navigateUp) }
|
||||
composable<FrpPolicy> { FrpPolicyScreen(::navigateUp) }
|
||||
composable<WipeData> { WipeDataScreen(::navigateUp) }
|
||||
|
||||
composable<Network> { NetworkScreen(::navigateUp) { navController.navigate(it) } }
|
||||
composable<Network> { NetworkScreen(::navigateUp, ::navigate) }
|
||||
composable<WiFi> {
|
||||
WifiScreen(::navigateUp, { navController.navigate(it) }) {
|
||||
val dest = navController.graph.findNode(AddNetwork)!!.id
|
||||
@@ -327,7 +331,7 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) {
|
||||
composable<AddNetwork> { AddNetworkScreen(it.arguments!!, ::navigateUp) }
|
||||
composable<WifiSecurityLevel> { WifiSecurityLevelScreen(::navigateUp) }
|
||||
composable<WifiSsidPolicyScreen> { WifiSsidPolicyScreen(::navigateUp) }
|
||||
composable<QueryNetworkStats> { NetworkStatsScreen(::navigateUp) { navController.navigate(it) } }
|
||||
composable<QueryNetworkStats> { NetworkStatsScreen(::navigateUp, ::navigate) }
|
||||
composable<NetworkStatsViewer>(mapOf(serializableNavTypePair<List<NetworkStatsViewer.Data>>())) {
|
||||
NetworkStatsViewerScreen(it.toRoute()) { navController.navigateUp() }
|
||||
}
|
||||
@@ -339,7 +343,7 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) {
|
||||
composable<PreferentialNetworkService> { PreferentialNetworkServiceScreen(::navigateUp) }
|
||||
composable<OverrideApn> { OverrideApnScreen(::navigateUp) }
|
||||
|
||||
composable<WorkProfile> { WorkProfileScreen(::navigateUp) { navController.navigate(it) } }
|
||||
composable<WorkProfile> { WorkProfileScreen(::navigateUp, ::navigate) }
|
||||
composable<OrganizationOwnedProfile> { OrganizationOwnedProfileScreen(::navigateUp) }
|
||||
composable<CreateWorkProfile> { CreateWorkProfileScreen(::navigateUp) }
|
||||
composable<SuspendPersonalApp> { SuspendPersonalAppScreen(::navigateUp) }
|
||||
@@ -370,7 +374,7 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) {
|
||||
}
|
||||
}
|
||||
|
||||
composable<Users> { UsersScreen(::navigateUp) { navController.navigate(it) } }
|
||||
composable<Users> { UsersScreen(::navigateUp, ::navigate) }
|
||||
composable<UserInfo> { UserInfoScreen(::navigateUp) }
|
||||
composable<UsersOptions> { UsersOptionsScreen(::navigateUp) }
|
||||
composable<UserOperation> { UserOperationScreen(::navigateUp) }
|
||||
@@ -379,7 +383,7 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) {
|
||||
composable<UserSessionMessage> { UserSessionMessageScreen(::navigateUp) }
|
||||
composable<AffiliationId> { AffiliationIdScreen(::navigateUp) }
|
||||
|
||||
composable<Password> { PasswordScreen(::navigateUp) { navController.navigate(it) } }
|
||||
composable<Password> { PasswordScreen(::navigateUp, ::navigate) }
|
||||
composable<PasswordInfo> { PasswordInfoScreen(::navigateUp) }
|
||||
composable<ResetPasswordToken> { ResetPasswordTokenScreen(::navigateUp) }
|
||||
composable<ResetPassword> { ResetPasswordScreen(::navigateUp) }
|
||||
@@ -387,7 +391,7 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) {
|
||||
composable<KeyguardDisabledFeatures> { KeyguardDisabledFeaturesScreen(::navigateUp) }
|
||||
composable<RequiredPasswordQuality> { RequiredPasswordQualityScreen(::navigateUp) }
|
||||
|
||||
composable<Settings> { SettingsScreen(::navigateUp) { navController.navigate(it) } }
|
||||
composable<Settings> { SettingsScreen(::navigateUp, ::navigate) }
|
||||
composable<SettingsOptions> { SettingsOptionsScreen(::navigateUp) }
|
||||
composable<Appearance> {
|
||||
val theme by vm.theme.collectAsStateWithLifecycle()
|
||||
|
||||
@@ -121,6 +121,8 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.res.painterResource
|
||||
@@ -483,6 +485,7 @@ fun AddNetworkScreen(data: Bundle, onNavigateUp: () -> Unit) {
|
||||
@Composable
|
||||
private fun AddNetworkScreen(wifiConfig: WifiConfiguration? = null, onNavigateUp: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val fm = LocalFocusManager.current
|
||||
var resultDialog by remember { mutableStateOf(false) }
|
||||
var createdNetworkId by remember { mutableIntStateOf(-1) }
|
||||
var createNetworkResult by remember { mutableIntStateOf(0) }
|
||||
@@ -614,21 +617,29 @@ private fun AddNetworkScreen(wifiConfig: WifiConfiguration? = null, onNavigateUp
|
||||
}
|
||||
}
|
||||
AnimatedVisibility(visible = useStaticIp, modifier = Modifier.padding(bottom = 8.dp)) {
|
||||
val gatewayFr = FocusRequester()
|
||||
val dnsFr = FocusRequester()
|
||||
Column {
|
||||
OutlinedTextField(
|
||||
value = ipAddress, onValueChange = { ipAddress = it },
|
||||
placeholder = { Text("192.168.1.2/24") }, label = { Text(stringResource(R.string.ip_address)) },
|
||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
|
||||
keyboardActions = KeyboardActions { gatewayFr.requestFocus() },
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp)
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = gatewayAddress, onValueChange = { gatewayAddress = it },
|
||||
placeholder = { Text("192.168.1.1") }, label = { Text(stringResource(R.string.gateway_address)) },
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp)
|
||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
|
||||
keyboardActions = KeyboardActions { dnsFr.requestFocus() },
|
||||
modifier = Modifier.focusRequester(gatewayFr).fillMaxWidth().padding(bottom = 4.dp)
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = dnsServers, onValueChange = { dnsServers = it },
|
||||
label = { Text(stringResource(R.string.dns_servers)) }, minLines = 2,
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp)
|
||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||
keyboardActions = KeyboardActions { fm.clearFocus() },
|
||||
modifier = Modifier.focusRequester(dnsFr).fillMaxWidth().padding(bottom = 4.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -648,19 +659,27 @@ private fun AddNetworkScreen(wifiConfig: WifiConfiguration? = null, onNavigateUp
|
||||
}
|
||||
}
|
||||
AnimatedVisibility(visible = useHttpProxy, modifier = Modifier.padding(bottom = 8.dp)) {
|
||||
val portFr = FocusRequester()
|
||||
val exclListFr = FocusRequester()
|
||||
Column {
|
||||
OutlinedTextField(
|
||||
value = httpProxyHost, onValueChange = { httpProxyHost = it }, label = { Text(stringResource(R.string.host)) },
|
||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
|
||||
keyboardActions = KeyboardActions { portFr.requestFocus() },
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp)
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = httpProxyPort, onValueChange = { httpProxyPort = it }, label = { Text(stringResource(R.string.port)) },
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp)
|
||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next, keyboardType = KeyboardType.Number),
|
||||
keyboardActions = KeyboardActions { exclListFr.requestFocus() },
|
||||
modifier = Modifier.focusRequester(portFr).fillMaxWidth().padding(bottom = 4.dp)
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = httpProxyExclList, onValueChange = { httpProxyExclList = it }, label = { Text(stringResource(R.string.excluded_hosts)) },
|
||||
minLines = 2, placeholder = { Text("example.com\n*.example.com") },
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp)
|
||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||
keyboardActions = KeyboardActions { fm.clearFocus() },
|
||||
modifier = Modifier.focusRequester(exclListFr).fillMaxWidth().padding(bottom = 4.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -884,6 +903,7 @@ fun NetworkStats.toBucketList(): List<NetworkStats.Bucket> {
|
||||
fun NetworkStatsScreen(onNavigateUp: () -> Unit, onNavigateToViewer: (NetworkStatsViewer) -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val deviceOwner = context.isDeviceOwner
|
||||
val fm = LocalFocusManager.current
|
||||
val nsm = context.getSystemService(NetworkStatsManager::class.java)
|
||||
val coroutine = rememberCoroutineScope()
|
||||
var activeTextField by remember { mutableStateOf(NetworkStatsActiveTextField.None) } //0:None, 1:Network type, 2:Start time, 3:End time
|
||||
@@ -999,6 +1019,8 @@ fun NetworkStatsScreen(onNavigateUp: () -> Unit, onNavigateToViewer: (NetworkSta
|
||||
label = { Text(stringResource(R.string.subscriber_id)) },
|
||||
isError = !readOnly && subscriberId.isNullOrBlank(),
|
||||
trailingIcon = { ExpandExposedTextFieldIcon(activeTextField == NetworkStatsActiveTextField.SubscriberId) },
|
||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||
keyboardActions = KeyboardActions { fm.clearFocus() },
|
||||
modifier = Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth().padding(bottom = 4.dp)
|
||||
)
|
||||
ExposedDropdownMenu(
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.bintianqi.owndroid.dpm
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.KeyguardManager
|
||||
import android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD
|
||||
import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_BIOMETRICS
|
||||
import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FACE
|
||||
import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL
|
||||
@@ -29,7 +28,6 @@ import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED
|
||||
import android.app.admin.DevicePolicyManager.RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT
|
||||
import android.app.admin.DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build.VERSION
|
||||
import android.os.UserManager
|
||||
import android.widget.Toast
|
||||
@@ -67,12 +65,13 @@ import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.ContextCompat.startActivity
|
||||
import androidx.navigation.NavHostController
|
||||
import com.bintianqi.owndroid.R
|
||||
import com.bintianqi.owndroid.SharedPrefs
|
||||
import com.bintianqi.owndroid.showOperationResultToast
|
||||
import com.bintianqi.owndroid.ui.CardItem
|
||||
import com.bintianqi.owndroid.ui.CheckBoxItem
|
||||
import com.bintianqi.owndroid.ui.FullWidthCheckBoxItem
|
||||
import com.bintianqi.owndroid.ui.FullWidthRadioButtonItem
|
||||
import com.bintianqi.owndroid.ui.FunctionItem
|
||||
import com.bintianqi.owndroid.ui.InfoCard
|
||||
import com.bintianqi.owndroid.ui.MyScaffold
|
||||
@@ -219,15 +218,17 @@ fun PasswordInfoScreen(onNavigateUp: () -> Unit) {
|
||||
val receiver = context.getReceiver()
|
||||
val deviceOwner = context.isDeviceOwner
|
||||
val profileOwner = context.isProfileOwner
|
||||
var dialog by remember { mutableIntStateOf(0) } // 0:none, 1:password complexity
|
||||
MyScaffold(R.string.password_info, 8.dp, onNavigateUp) {
|
||||
if(VERSION.SDK_INT >= 29) {
|
||||
val passwordComplexity = mapOf(
|
||||
PASSWORD_COMPLEXITY_NONE to R.string.password_complexity_none,
|
||||
PASSWORD_COMPLEXITY_LOW to R.string.password_complexity_low,
|
||||
PASSWORD_COMPLEXITY_MEDIUM to R.string.password_complexity_medium,
|
||||
PASSWORD_COMPLEXITY_HIGH to R.string.password_complexity_high
|
||||
)
|
||||
CardItem(R.string.current_password_complexity, passwordComplexity[dpm.passwordComplexity] ?: R.string.unknown)
|
||||
val text = when(dpm.passwordComplexity) {
|
||||
PASSWORD_COMPLEXITY_NONE -> R.string.none
|
||||
PASSWORD_COMPLEXITY_LOW -> R.string.low
|
||||
PASSWORD_COMPLEXITY_MEDIUM -> R.string.medium
|
||||
PASSWORD_COMPLEXITY_HIGH -> R.string.high
|
||||
else -> R.string.unknown
|
||||
}
|
||||
CardItem(R.string.current_password_complexity, text) { dialog = 1 }
|
||||
}
|
||||
if(deviceOwner || profileOwner) {
|
||||
CardItem(R.string.password_sufficient, dpm.isActivePasswordSufficient.yesOrNo)
|
||||
@@ -236,6 +237,15 @@ fun PasswordInfoScreen(onNavigateUp: () -> Unit) {
|
||||
CardItem(R.string.unified_password, dpm.isUsingUnifiedPassword(receiver).yesOrNo)
|
||||
}
|
||||
}
|
||||
if(dialog != 0) AlertDialog(
|
||||
text = { Text(stringResource(R.string.info_password_complexity)) },
|
||||
confirmButton = {
|
||||
TextButton({ dialog = 0 }) {
|
||||
Text(stringResource(R.string.confirm))
|
||||
}
|
||||
},
|
||||
onDismissRequest = { dialog = 0 }
|
||||
)
|
||||
}
|
||||
|
||||
@Serializable object ResetPasswordToken
|
||||
@@ -430,34 +440,29 @@ fun RequiredPasswordComplexityScreen(onNavigateUp: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val passwordComplexity = mapOf(
|
||||
PASSWORD_COMPLEXITY_NONE to R.string.password_complexity_none,
|
||||
PASSWORD_COMPLEXITY_LOW to R.string.password_complexity_low,
|
||||
PASSWORD_COMPLEXITY_MEDIUM to R.string.password_complexity_medium,
|
||||
PASSWORD_COMPLEXITY_HIGH to R.string.password_complexity_high
|
||||
PASSWORD_COMPLEXITY_NONE to R.string.none,
|
||||
PASSWORD_COMPLEXITY_LOW to R.string.low,
|
||||
PASSWORD_COMPLEXITY_MEDIUM to R.string.medium,
|
||||
PASSWORD_COMPLEXITY_HIGH to R.string.high
|
||||
)
|
||||
var selectedItem by remember { mutableIntStateOf(PASSWORD_COMPLEXITY_NONE) }
|
||||
LaunchedEffect(Unit) { selectedItem = dpm.requiredPasswordComplexity }
|
||||
MyScaffold(R.string.required_password_complexity, 8.dp, onNavigateUp) {
|
||||
MyScaffold(R.string.required_password_complexity, 0.dp, onNavigateUp) {
|
||||
passwordComplexity.forEach {
|
||||
RadioButtonItem(it.value, selectedItem == it.key) { selectedItem = it.key }
|
||||
FullWidthRadioButtonItem(it.value, selectedItem == it.key) { selectedItem = it.key }
|
||||
}
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
Button(
|
||||
onClick = {
|
||||
dpm.requiredPasswordComplexity = selectedItem
|
||||
selectedItem = dpm.requiredPasswordComplexity
|
||||
context.showOperationResultToast(true)
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp, horizontal = 8.dp)
|
||||
) {
|
||||
Text(text = stringResource(R.string.apply))
|
||||
}
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
Button(
|
||||
onClick = { context.startActivity(Intent(ACTION_SET_NEW_PASSWORD)) },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(stringResource(R.string.require_set_new_password))
|
||||
}
|
||||
InfoCard(R.string.info_password_complexity, 8.dp)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,20 +499,19 @@ fun KeyguardDisabledFeaturesScreen(onNavigateUp: () -> Unit) {
|
||||
}
|
||||
LaunchedEffect(mode) { if(mode != 2) flag = dpm.getKeyguardDisabledFeatures(receiver) }
|
||||
LaunchedEffect(Unit) { refresh() }
|
||||
MyScaffold(R.string.disable_keyguard_features, 8.dp, onNavigateUp) {
|
||||
RadioButtonItem(R.string.enable_all, mode == 0) { mode = 0 }
|
||||
RadioButtonItem(R.string.disable_all, mode == 1) { mode = 1 }
|
||||
RadioButtonItem(R.string.custom, mode == 2) { mode = 2 }
|
||||
MyScaffold(R.string.disable_keyguard_features, 0.dp, onNavigateUp) {
|
||||
FullWidthRadioButtonItem(R.string.enable_all, mode == 0) { mode = 0 }
|
||||
FullWidthRadioButtonItem(R.string.disable_all, mode == 1) { mode = 1 }
|
||||
FullWidthRadioButtonItem(R.string.custom, mode == 2) { mode = 2 }
|
||||
AnimatedVisibility(mode == 2) {
|
||||
Column {
|
||||
flagsLiat.forEach {
|
||||
CheckBoxItem(it.first, flag and it.second == it.second) { checked ->
|
||||
FullWidthCheckBoxItem(it.first, flag and it.second == it.second) { checked ->
|
||||
flag = if(checked) flag or it.second else flag and (flag xor it.second)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
Button(
|
||||
onClick = {
|
||||
val disabledFeatures = if(mode == 0) KEYGUARD_DISABLE_FEATURES_NONE else if(mode == 1) KEYGUARD_DISABLE_FEATURES_ALL else flag
|
||||
@@ -515,7 +519,7 @@ fun KeyguardDisabledFeaturesScreen(onNavigateUp: () -> Unit) {
|
||||
refresh()
|
||||
context.showOperationResultToast(true)
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp)
|
||||
) {
|
||||
Text(text = stringResource(R.string.apply))
|
||||
}
|
||||
|
||||
@@ -20,18 +20,17 @@ import androidx.annotation.StringRes
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.outlined.Edit
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.material3.MaterialTheme.colorScheme
|
||||
import androidx.compose.material3.MaterialTheme.typography
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
@@ -497,7 +496,7 @@ fun DeviceOwnerScreen(onNavigateUp: () -> Unit) {
|
||||
}
|
||||
|
||||
@Suppress("InlinedApi")
|
||||
private enum class DelegatedScope(val id: String, @StringRes val string: Int, val requiresApi: Int = 0) {
|
||||
enum class DelegatedScope(val id: String, @StringRes val string: Int, val requiresApi: Int = 0) {
|
||||
AppRestrictions(DevicePolicyManager.DELEGATION_APP_RESTRICTIONS, R.string.manage_application_restrictions),
|
||||
BlockUninstall(DevicePolicyManager.DELEGATION_BLOCK_UNINSTALL, R.string.block_uninstall),
|
||||
CertInstall(DevicePolicyManager.DELEGATION_CERT_INSTALL, R.string.manage_certificates),
|
||||
@@ -515,13 +514,10 @@ private enum class DelegatedScope(val id: String, @StringRes val string: Int, va
|
||||
|
||||
@RequiresApi(26)
|
||||
@Composable
|
||||
fun DelegatedAdminsScreen(onNavigateUp: () -> Unit) {
|
||||
fun DelegatedAdminsScreen(onNavigateUp: () -> Unit, onNavigate: (AddDelegatedAdmin) -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
var dialog by rememberSaveable { mutableIntStateOf(0) } // 0:None, 1:Edit, 2:Add
|
||||
var inputPackageName by rememberSaveable { mutableStateOf("") }
|
||||
var selectedScopes by rememberSaveable { mutableStateOf(listOf<String>()) }
|
||||
val packages = remember { mutableStateMapOf<String, MutableList<DelegatedScope>>() }
|
||||
fun refresh() {
|
||||
val list = mutableMapOf<String, MutableList<DelegatedScope>>()
|
||||
@@ -542,81 +538,91 @@ fun DelegatedAdminsScreen(onNavigateUp: () -> Unit) {
|
||||
LaunchedEffect(Unit) { refresh() }
|
||||
MyScaffold(R.string.delegated_admins, 0.dp, onNavigateUp) {
|
||||
packages.forEach { (pkg, scopes) ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { inputPackageName = pkg; selectedScopes = scopes.map { it.id }; dialog = 1 }
|
||||
.padding(horizontal = 12.dp, vertical = 8.dp)
|
||||
Row(
|
||||
Modifier.fillMaxWidth().padding(vertical = 8.dp).padding(start = 14.dp, end = 8.dp),
|
||||
Arrangement.SpaceBetween
|
||||
) {
|
||||
Text(pkg, style = typography.titleLarge)
|
||||
Text(scopes.size.toString() + " " + stringResource(R.string.delegated_scope))
|
||||
Column {
|
||||
Text(pkg, style = typography.titleMedium)
|
||||
Text(
|
||||
scopes.size.toString() + " " + stringResource(R.string.delegated_scope),
|
||||
color = colorScheme.onSurfaceVariant, style = typography.bodyMedium
|
||||
)
|
||||
}
|
||||
IconButton({ onNavigate(AddDelegatedAdmin(pkg, scopes)) }) {
|
||||
Icon(Icons.Outlined.Edit, stringResource(R.string.edit))
|
||||
}
|
||||
}
|
||||
}
|
||||
if(packages.isEmpty())
|
||||
Text(
|
||||
stringResource(R.string.none),
|
||||
color = colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally).padding(vertical = 4.dp)
|
||||
)
|
||||
if(packages.isEmpty()) Text(
|
||||
stringResource(R.string.none),
|
||||
color = colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally).padding(vertical = 4.dp)
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { inputPackageName = ""; selectedScopes = emptyList(); dialog = 2 }
|
||||
.padding(vertical = 10.dp, horizontal = 12.dp),
|
||||
.clickable { onNavigate(AddDelegatedAdmin()) }
|
||||
.padding(12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(Icons.Default.Add, null, modifier = Modifier.padding(end = 12.dp))
|
||||
Text(stringResource(R.string.add_delegated_admin), style = typography.titleLarge)
|
||||
Text(stringResource(R.string.add_delegated_admin), style = typography.titleMedium)
|
||||
}
|
||||
if(dialog != 0) {
|
||||
val choosePackage = rememberLauncherForActivityResult(ChoosePackageContract()) { result ->
|
||||
result?.let { inputPackageName = it }
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable data class AddDelegatedAdmin(val pkg: String = "", val scopes: List<DelegatedScope> = emptyList())
|
||||
|
||||
@RequiresApi(26)
|
||||
@Composable
|
||||
fun AddDelegatedAdminScreen(data: AddDelegatedAdmin, onNavigateUp: () -> Unit) {
|
||||
val updateMode = data.pkg.isNotEmpty()
|
||||
val fm = LocalFocusManager.current
|
||||
val context = LocalContext.current
|
||||
var input by remember { mutableStateOf(data.pkg) }
|
||||
val scopes = remember { mutableStateListOf(*data.scopes.toTypedArray()) }
|
||||
val choosePackage = rememberLauncherForActivityResult(ChoosePackageContract()) { result ->
|
||||
result?.let { input = it }
|
||||
}
|
||||
MyScaffold(if(updateMode) R.string.place_holder else R.string.add_delegated_admin, 0.dp, onNavigateUp, !updateMode) {
|
||||
OutlinedTextField(
|
||||
value = input, onValueChange = { input = it },
|
||||
label = { Text(stringResource(R.string.package_name)) },
|
||||
trailingIcon = {
|
||||
if(!updateMode) IconButton({ choosePackage.launch(null) }) {
|
||||
Icon(painterResource(R.drawable.list_fill0), null)
|
||||
}
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Ascii, imeAction = ImeAction.Done),
|
||||
keyboardActions = KeyboardActions { fm.clearFocus() },
|
||||
readOnly = updateMode,
|
||||
modifier = Modifier.fillMaxWidth().padding(8.dp)
|
||||
)
|
||||
DelegatedScope.entries.filter { VERSION.SDK_INT >= it.requiresApi }.forEach {scope ->
|
||||
FullWidthCheckBoxItem(scope.string, scope in scopes) {
|
||||
if(it) scopes += scope else scopes -= scope
|
||||
}
|
||||
AlertDialog(
|
||||
text = {
|
||||
val fm = LocalFocusManager.current
|
||||
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
|
||||
OutlinedTextField(
|
||||
value = inputPackageName, onValueChange = { inputPackageName = it },
|
||||
label = { Text(stringResource(R.string.package_name)) },
|
||||
trailingIcon = {
|
||||
if(dialog == 2) IconButton({ choosePackage.launch(null) }) {
|
||||
Icon(painterResource(R.drawable.list_fill0), null)
|
||||
}
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Ascii, imeAction = ImeAction.Done),
|
||||
keyboardActions = KeyboardActions { fm.clearFocus() },
|
||||
readOnly = dialog == 1,
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp)
|
||||
)
|
||||
DelegatedScope.entries.forEach { scope ->
|
||||
if(VERSION.SDK_INT >= scope.requiresApi) {
|
||||
CheckBoxItem(scope.string, scope.id in selectedScopes) {
|
||||
if(it) selectedScopes += scope.id else selectedScopes -= scope.id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
dpm.setDelegatedScopes(receiver, inputPackageName, selectedScopes)
|
||||
refresh()
|
||||
dialog = 0
|
||||
},
|
||||
enabled = inputPackageName.isNotBlank()
|
||||
) {
|
||||
Text(stringResource(if(dialog == 1) R.string.apply else R.string.add))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton({ dialog = 0 }) {
|
||||
Text(stringResource(R.string.cancel))
|
||||
}
|
||||
},
|
||||
onDismissRequest = { dialog = 0 }
|
||||
)
|
||||
}
|
||||
Button(
|
||||
onClick = {
|
||||
context.getDPM().setDelegatedScopes(context.getReceiver(), input, scopes.map { it.id })
|
||||
onNavigateUp()
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp, vertical = 4.dp),
|
||||
enabled = input.isNotBlank() && (!updateMode || scopes.toList() != data.scopes)
|
||||
) {
|
||||
Text(stringResource(if(updateMode) R.string.update else R.string.add))
|
||||
}
|
||||
if(updateMode) Button(
|
||||
onClick = {
|
||||
context.getDPM().setDelegatedScopes(context.getReceiver(), input, emptyList())
|
||||
onNavigateUp()
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp),
|
||||
colors = ButtonDefaults.buttonColors(colorScheme.error, colorScheme.onError)
|
||||
) {
|
||||
Text(stringResource(R.string.delete))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +133,7 @@ import com.bintianqi.owndroid.humanReadableDate
|
||||
import com.bintianqi.owndroid.parseDate
|
||||
import com.bintianqi.owndroid.showOperationResultToast
|
||||
import com.bintianqi.owndroid.ui.CheckBoxItem
|
||||
import com.bintianqi.owndroid.ui.FullWidthRadioButtonItem
|
||||
import com.bintianqi.owndroid.ui.FunctionItem
|
||||
import com.bintianqi.owndroid.ui.InfoCard
|
||||
import com.bintianqi.owndroid.ui.ListItem
|
||||
@@ -847,13 +848,13 @@ fun ContentProtectionPolicyScreen(onNavigateUp: () -> Unit) {
|
||||
var policy by remember { mutableIntStateOf(DevicePolicyManager.CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY) }
|
||||
fun refresh() { policy = dpm.getContentProtectionPolicy(receiver) }
|
||||
LaunchedEffect(Unit) { refresh() }
|
||||
MyScaffold(R.string.content_protection_policy, 8.dp, onNavigateUp) {
|
||||
MyScaffold(R.string.content_protection_policy, 0.dp, onNavigateUp) {
|
||||
mapOf(
|
||||
DevicePolicyManager.CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY to R.string.not_controlled_by_policy,
|
||||
DevicePolicyManager.CONTENT_PROTECTION_ENABLED to R.string.enabled,
|
||||
DevicePolicyManager.CONTENT_PROTECTION_DISABLED to R.string.disabled
|
||||
).forEach { (policyId, string) ->
|
||||
RadioButtonItem(string, policy == policyId) { policy = policyId }
|
||||
FullWidthRadioButtonItem(string, policy == policyId) { policy = policyId }
|
||||
}
|
||||
Button(
|
||||
onClick = {
|
||||
@@ -861,11 +862,11 @@ fun ContentProtectionPolicyScreen(onNavigateUp: () -> Unit) {
|
||||
refresh()
|
||||
context.showOperationResultToast(true)
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp)
|
||||
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp, horizontal = 8.dp)
|
||||
) {
|
||||
Text(stringResource(R.string.apply))
|
||||
}
|
||||
InfoCard(R.string.info_content_protection_policy)
|
||||
InfoCard(R.string.info_content_protection_policy, 8.dp)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -878,21 +879,27 @@ fun PermissionPolicyScreen(onNavigateUp: () -> Unit) {
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
var selectedPolicy by remember { mutableIntStateOf(dpm.getPermissionPolicy(receiver)) }
|
||||
MyScaffold(R.string.permission_policy, 8.dp, onNavigateUp) {
|
||||
RadioButtonItem(R.string.default_stringres, selectedPolicy == PERMISSION_POLICY_PROMPT) { selectedPolicy = PERMISSION_POLICY_PROMPT }
|
||||
RadioButtonItem(R.string.auto_grant, selectedPolicy == PERMISSION_POLICY_AUTO_GRANT) { selectedPolicy = PERMISSION_POLICY_AUTO_GRANT }
|
||||
RadioButtonItem(R.string.auto_deny, selectedPolicy == PERMISSION_POLICY_AUTO_DENY) { selectedPolicy = PERMISSION_POLICY_AUTO_DENY }
|
||||
MyScaffold(R.string.permission_policy, 0.dp, onNavigateUp) {
|
||||
FullWidthRadioButtonItem(R.string.default_stringres, selectedPolicy == PERMISSION_POLICY_PROMPT) {
|
||||
selectedPolicy = PERMISSION_POLICY_PROMPT
|
||||
}
|
||||
FullWidthRadioButtonItem(R.string.auto_grant, selectedPolicy == PERMISSION_POLICY_AUTO_GRANT) {
|
||||
selectedPolicy = PERMISSION_POLICY_AUTO_GRANT
|
||||
}
|
||||
FullWidthRadioButtonItem(R.string.auto_deny, selectedPolicy == PERMISSION_POLICY_AUTO_DENY) {
|
||||
selectedPolicy = PERMISSION_POLICY_AUTO_DENY
|
||||
}
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
Button(
|
||||
onClick = {
|
||||
dpm.setPermissionPolicy(receiver,selectedPolicy)
|
||||
context.showOperationResultToast(true)
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp)
|
||||
) {
|
||||
Text(stringResource(R.string.apply))
|
||||
}
|
||||
InfoCard(R.string.info_permission_policy)
|
||||
InfoCard(R.string.info_permission_policy, 8.dp)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -904,10 +911,12 @@ fun MtePolicyScreen(onNavigateUp: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
var selectedMtePolicy by remember { mutableIntStateOf(dpm.mtePolicy) }
|
||||
MyScaffold(R.string.mte_policy, 8.dp, onNavigateUp) {
|
||||
RadioButtonItem(R.string.decide_by_user, selectedMtePolicy == MTE_NOT_CONTROLLED_BY_POLICY) { selectedMtePolicy = MTE_NOT_CONTROLLED_BY_POLICY }
|
||||
RadioButtonItem(R.string.enabled, selectedMtePolicy == MTE_ENABLED) { selectedMtePolicy = MTE_ENABLED }
|
||||
RadioButtonItem(R.string.disabled, selectedMtePolicy == MTE_DISABLED) { selectedMtePolicy = MTE_DISABLED }
|
||||
MyScaffold(R.string.mte_policy, 0.dp, onNavigateUp) {
|
||||
FullWidthRadioButtonItem(R.string.decide_by_user, selectedMtePolicy == MTE_NOT_CONTROLLED_BY_POLICY) {
|
||||
selectedMtePolicy = MTE_NOT_CONTROLLED_BY_POLICY
|
||||
}
|
||||
FullWidthRadioButtonItem(R.string.enabled, selectedMtePolicy == MTE_ENABLED) { selectedMtePolicy = MTE_ENABLED }
|
||||
FullWidthRadioButtonItem(R.string.disabled, selectedMtePolicy == MTE_DISABLED) { selectedMtePolicy = MTE_DISABLED }
|
||||
Button(
|
||||
onClick = {
|
||||
try {
|
||||
@@ -918,11 +927,11 @@ fun MtePolicyScreen(onNavigateUp: () -> Unit) {
|
||||
}
|
||||
selectedMtePolicy = dpm.mtePolicy
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp, horizontal = 8.dp)
|
||||
) {
|
||||
Text(stringResource(R.string.apply))
|
||||
}
|
||||
InfoCard(R.string.info_mte_policy)
|
||||
InfoCard(R.string.info_mte_policy, 8.dp)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -934,62 +943,64 @@ fun NearbyStreamingPolicyScreen(onNavigateUp: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
var appPolicy by remember { mutableIntStateOf(dpm.nearbyAppStreamingPolicy) }
|
||||
MyScaffold(R.string.nearby_streaming_policy, 8.dp, onNavigateUp) {
|
||||
Spacer(Modifier.padding(vertical = 10.dp))
|
||||
Text(text = stringResource(R.string.nearby_app_streaming), style = typography.titleLarge)
|
||||
Spacer(Modifier.padding(vertical = 3.dp))
|
||||
RadioButtonItem(
|
||||
MyScaffold(R.string.nearby_streaming_policy, 0.dp, onNavigateUp, false) {
|
||||
Text(
|
||||
stringResource(R.string.nearby_app_streaming),
|
||||
Modifier.padding(start = 8.dp, top = 10.dp, bottom = 4.dp), style = typography.titleLarge
|
||||
)
|
||||
FullWidthRadioButtonItem(
|
||||
R.string.decide_by_user,
|
||||
appPolicy == NEARBY_STREAMING_NOT_CONTROLLED_BY_POLICY
|
||||
) { appPolicy = NEARBY_STREAMING_NOT_CONTROLLED_BY_POLICY }
|
||||
RadioButtonItem(R.string.enabled, appPolicy == NEARBY_STREAMING_ENABLED) { appPolicy = NEARBY_STREAMING_ENABLED }
|
||||
RadioButtonItem(R.string.disabled, appPolicy == NEARBY_STREAMING_DISABLED) { appPolicy = NEARBY_STREAMING_DISABLED }
|
||||
RadioButtonItem(
|
||||
FullWidthRadioButtonItem(R.string.enabled, appPolicy == NEARBY_STREAMING_ENABLED) { appPolicy = NEARBY_STREAMING_ENABLED }
|
||||
FullWidthRadioButtonItem(R.string.disabled, appPolicy == NEARBY_STREAMING_DISABLED) { appPolicy = NEARBY_STREAMING_DISABLED }
|
||||
FullWidthRadioButtonItem(
|
||||
R.string.enable_if_secure_enough,
|
||||
appPolicy == NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY
|
||||
) { appPolicy = NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY }
|
||||
Spacer(Modifier.padding(vertical = 3.dp))
|
||||
Button(
|
||||
onClick = {
|
||||
dpm.nearbyAppStreamingPolicy = appPolicy
|
||||
appPolicy = dpm.nearbyAppStreamingPolicy
|
||||
context.showOperationResultToast(true)
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp, horizontal = 8.dp)
|
||||
) {
|
||||
Text(stringResource(R.string.apply))
|
||||
}
|
||||
InfoCard(R.string.info_nearby_app_streaming_policy)
|
||||
InfoCard(R.string.info_nearby_app_streaming_policy, 8.dp)
|
||||
var notificationPolicy by remember { mutableIntStateOf(dpm.nearbyNotificationStreamingPolicy) }
|
||||
Spacer(Modifier.padding(vertical = 10.dp))
|
||||
Text(text = stringResource(R.string.nearby_notification_streaming), style = typography.titleLarge)
|
||||
Spacer(Modifier.padding(vertical = 3.dp))
|
||||
RadioButtonItem(
|
||||
Text(
|
||||
stringResource(R.string.nearby_notification_streaming),
|
||||
Modifier.padding(start = 8.dp, top = 10.dp, bottom = 4.dp), style = typography.titleLarge
|
||||
)
|
||||
FullWidthRadioButtonItem(
|
||||
R.string.decide_by_user,
|
||||
notificationPolicy == NEARBY_STREAMING_NOT_CONTROLLED_BY_POLICY
|
||||
) { notificationPolicy = NEARBY_STREAMING_NOT_CONTROLLED_BY_POLICY }
|
||||
RadioButtonItem(
|
||||
FullWidthRadioButtonItem(
|
||||
R.string.enabled,
|
||||
notificationPolicy == NEARBY_STREAMING_ENABLED
|
||||
) { notificationPolicy = NEARBY_STREAMING_ENABLED }
|
||||
RadioButtonItem(
|
||||
FullWidthRadioButtonItem(
|
||||
R.string.disabled,
|
||||
notificationPolicy == NEARBY_STREAMING_DISABLED
|
||||
) { notificationPolicy = NEARBY_STREAMING_DISABLED }
|
||||
RadioButtonItem(
|
||||
FullWidthRadioButtonItem(
|
||||
R.string.enable_if_secure_enough,
|
||||
notificationPolicy == NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY
|
||||
) { notificationPolicy = NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY }
|
||||
Spacer(Modifier.padding(vertical = 3.dp))
|
||||
Button(
|
||||
onClick = {
|
||||
dpm.nearbyNotificationStreamingPolicy = notificationPolicy
|
||||
notificationPolicy = dpm.nearbyNotificationStreamingPolicy
|
||||
context.showOperationResultToast(true)
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp, horizontal = 8.dp)
|
||||
) {
|
||||
Text(stringResource(R.string.apply))
|
||||
}
|
||||
InfoCard(R.string.info_nearby_notification_streaming_policy)
|
||||
InfoCard(R.string.info_nearby_notification_streaming_policy, 8.dp)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1586,7 +1597,8 @@ fun FrpPolicyScreen(onNavigateUp: () -> Unit) {
|
||||
onClick = {
|
||||
accountList += inputAccount
|
||||
inputAccount = ""
|
||||
}
|
||||
},
|
||||
enabled = inputAccount.isNotBlank()
|
||||
) {
|
||||
Icon(imageVector = Icons.Default.Add, contentDescription = stringResource(R.string.add))
|
||||
}
|
||||
@@ -1733,87 +1745,81 @@ fun WipeDataScreen(onNavigateUp: () -> Unit) {
|
||||
|
||||
@Serializable object SetSystemUpdatePolicy
|
||||
|
||||
@RequiresApi(23)
|
||||
@Composable
|
||||
fun SystemUpdatePolicy(onNavigateUp: () -> Unit) {
|
||||
fun SystemUpdatePolicyScreen(onNavigateUp: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val focusMgr = LocalFocusManager.current
|
||||
MyScaffold(R.string.system_update_policy, 8.dp, onNavigateUp) {
|
||||
if(VERSION.SDK_INT >= 23) {
|
||||
Column {
|
||||
var selectedPolicy by remember { mutableStateOf(dpm.systemUpdatePolicy?.policyType) }
|
||||
RadioButtonItem(
|
||||
R.string.system_update_policy_automatic,
|
||||
selectedPolicy == TYPE_INSTALL_AUTOMATIC
|
||||
) { selectedPolicy = TYPE_INSTALL_AUTOMATIC }
|
||||
RadioButtonItem(
|
||||
R.string.system_update_policy_install_windowed,
|
||||
selectedPolicy == TYPE_INSTALL_WINDOWED
|
||||
) { selectedPolicy = TYPE_INSTALL_WINDOWED }
|
||||
RadioButtonItem(
|
||||
R.string.system_update_policy_postpone,
|
||||
selectedPolicy == TYPE_POSTPONE
|
||||
) { selectedPolicy = TYPE_POSTPONE }
|
||||
RadioButtonItem(R.string.none, selectedPolicy == null) { selectedPolicy = null }
|
||||
var windowedPolicyStart by remember { mutableStateOf("") }
|
||||
var windowedPolicyEnd by remember { mutableStateOf("") }
|
||||
AnimatedVisibility(selectedPolicy == 2) {
|
||||
Column {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
OutlinedTextField(
|
||||
value = windowedPolicyStart,
|
||||
label = { Text(stringResource(R.string.start_time)) },
|
||||
onValueChange = { windowedPolicyStart = it },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
|
||||
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
|
||||
modifier = Modifier.fillMaxWidth(0.49F)
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = windowedPolicyEnd,
|
||||
onValueChange = {windowedPolicyEnd = it },
|
||||
label = { Text(stringResource(R.string.end_time)) },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
|
||||
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
|
||||
modifier = Modifier.fillMaxWidth(0.96F).padding(bottom = 2.dp)
|
||||
)
|
||||
}
|
||||
Text(text = stringResource(R.string.minutes_in_one_day))
|
||||
}
|
||||
}
|
||||
Button(
|
||||
onClick = {
|
||||
val policy =
|
||||
when(selectedPolicy) {
|
||||
TYPE_INSTALL_AUTOMATIC-> SystemUpdatePolicy.createAutomaticInstallPolicy()
|
||||
TYPE_INSTALL_WINDOWED-> SystemUpdatePolicy.createWindowedInstallPolicy(windowedPolicyStart.toInt(), windowedPolicyEnd.toInt())
|
||||
TYPE_POSTPONE-> SystemUpdatePolicy.createPostponeInstallPolicy()
|
||||
else -> null
|
||||
}
|
||||
dpm.setSystemUpdatePolicy(receiver,policy)
|
||||
context.showOperationResultToast(true)
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth().padding(top = 8.dp)
|
||||
) {
|
||||
Text(stringResource(R.string.apply))
|
||||
MyScaffold(R.string.system_update_policy, 0.dp, onNavigateUp) {
|
||||
var selectedPolicy by remember { mutableStateOf(dpm.systemUpdatePolicy?.policyType) }
|
||||
FullWidthRadioButtonItem(
|
||||
R.string.system_update_policy_automatic,
|
||||
selectedPolicy == TYPE_INSTALL_AUTOMATIC
|
||||
) { selectedPolicy = TYPE_INSTALL_AUTOMATIC }
|
||||
FullWidthRadioButtonItem(
|
||||
R.string.system_update_policy_install_windowed,
|
||||
selectedPolicy == TYPE_INSTALL_WINDOWED
|
||||
) { selectedPolicy = TYPE_INSTALL_WINDOWED }
|
||||
FullWidthRadioButtonItem(
|
||||
R.string.system_update_policy_postpone,
|
||||
selectedPolicy == TYPE_POSTPONE
|
||||
) { selectedPolicy = TYPE_POSTPONE }
|
||||
FullWidthRadioButtonItem(R.string.none, selectedPolicy == null) { selectedPolicy = null }
|
||||
var windowedPolicyStart by remember { mutableStateOf("") }
|
||||
var windowedPolicyEnd by remember { mutableStateOf("") }
|
||||
AnimatedVisibility(selectedPolicy == 2) {
|
||||
Column(Modifier.padding(horizontal = 8.dp)) {
|
||||
Row(Modifier.fillMaxWidth().padding(vertical = 4.dp), Arrangement.SpaceBetween) {
|
||||
OutlinedTextField(
|
||||
value = windowedPolicyStart,
|
||||
label = { Text(stringResource(R.string.start_time)) },
|
||||
onValueChange = { windowedPolicyStart = it },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
|
||||
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
|
||||
modifier = Modifier.fillMaxWidth(0.49F)
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = windowedPolicyEnd,
|
||||
onValueChange = {windowedPolicyEnd = it },
|
||||
label = { Text(stringResource(R.string.end_time)) },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
|
||||
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
|
||||
modifier = Modifier.fillMaxWidth(0.96F).padding(bottom = 2.dp)
|
||||
)
|
||||
}
|
||||
Text(stringResource(R.string.minutes_in_one_day), color = colorScheme.onSurfaceVariant, style = typography.bodyMedium)
|
||||
}
|
||||
}
|
||||
Button(
|
||||
onClick = {
|
||||
val policy =
|
||||
when(selectedPolicy) {
|
||||
TYPE_INSTALL_AUTOMATIC-> SystemUpdatePolicy.createAutomaticInstallPolicy()
|
||||
TYPE_INSTALL_WINDOWED-> SystemUpdatePolicy.createWindowedInstallPolicy(windowedPolicyStart.toInt(), windowedPolicyEnd.toInt())
|
||||
TYPE_POSTPONE-> SystemUpdatePolicy.createPostponeInstallPolicy()
|
||||
else -> null
|
||||
}
|
||||
dpm.setSystemUpdatePolicy(receiver,policy)
|
||||
context.showOperationResultToast(true)
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp, horizontal = 8.dp)
|
||||
) {
|
||||
Text(stringResource(R.string.apply))
|
||||
}
|
||||
if(VERSION.SDK_INT >= 26) {
|
||||
Spacer(Modifier.padding(vertical = 10.dp))
|
||||
val sysUpdateInfo = dpm.getPendingSystemUpdate(receiver)
|
||||
Column {
|
||||
Column(Modifier.padding(8.dp)) {
|
||||
if(sysUpdateInfo != null) {
|
||||
Text(text = stringResource(R.string.update_received_time, Date(sysUpdateInfo.receivedTime)))
|
||||
val securityStateDesc = when(sysUpdateInfo.securityPatchState) {
|
||||
SystemUpdateInfo.SECURITY_PATCH_STATE_UNKNOWN -> stringResource(R.string.unknown)
|
||||
SystemUpdateInfo.SECURITY_PATCH_STATE_TRUE -> "true"
|
||||
else->"false"
|
||||
val securityPatchStateText = when(sysUpdateInfo.securityPatchState) {
|
||||
SystemUpdateInfo.SECURITY_PATCH_STATE_FALSE -> R.string.no
|
||||
SystemUpdateInfo.SECURITY_PATCH_STATE_TRUE -> R.string.yes
|
||||
else -> R.string.unknown
|
||||
}
|
||||
Text(text = stringResource(R.string.is_security_patch, securityStateDesc))
|
||||
}else{
|
||||
Text(text = stringResource(R.string.is_security_patch, stringResource(securityPatchStateText)))
|
||||
} else {
|
||||
Text(text = stringResource(R.string.no_system_update))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,10 @@ fun UsersScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
|
||||
if(bitmap != null) changeUserIconDialog = true
|
||||
}
|
||||
}
|
||||
FunctionItem(R.string.change_user_icon, icon = R.drawable.account_circle_fill0) { launcher.launch("image/*") }
|
||||
FunctionItem(R.string.change_user_icon, icon = R.drawable.account_circle_fill0) {
|
||||
Toast.makeText(context, R.string.select_an_image, Toast.LENGTH_SHORT).show()
|
||||
launcher.launch("image/*")
|
||||
}
|
||||
if(changeUserIconDialog == true) ChangeUserIconDialog(bitmap!!) { changeUserIconDialog = false }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 28 && deviceOwner) {
|
||||
@@ -432,7 +435,8 @@ fun AffiliationIdScreen(onNavigateUp: () -> Unit) {
|
||||
onClick = {
|
||||
list += input
|
||||
input = ""
|
||||
}
|
||||
},
|
||||
enabled = input.isNotEmpty()
|
||||
) {
|
||||
Icon(imageVector = Icons.Default.Add, contentDescription = stringResource(R.string.add))
|
||||
}
|
||||
@@ -453,7 +457,7 @@ fun AffiliationIdScreen(onNavigateUp: () -> Unit) {
|
||||
) {
|
||||
Text(stringResource(R.string.apply))
|
||||
}
|
||||
InfoCard(R.string.info_affiliated_id)
|
||||
InfoCard(R.string.info_affiliation_id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -272,12 +272,12 @@ fun ListItem(text: String, onDelete: () -> Unit) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun InfoCard(@StringRes strID: Int) {
|
||||
fun InfoCard(@StringRes strID: Int, horizonPadding: Dp = 0.dp) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 8.dp)
|
||||
.clip(RoundedCornerShape(10))
|
||||
.padding(vertical = 8.dp, horizontal = horizonPadding)
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.background(color = colorScheme.tertiaryContainer)
|
||||
.padding(8.dp)
|
||||
) {
|
||||
|
||||
Reference in New Issue
Block a user