mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-23 19:15:58 +00:00
ViewModel refactoring: Work profile part
close #169 Improve UI, fix #172 fix #165
This commit is contained in:
@@ -38,6 +38,7 @@
|
||||
<action android:name="android.app.action.PROVISION_MANAGED_PROFILE"/>
|
||||
<action android:name="android.app.action.MANAGED_PROFILE_PROVISIONED"/>
|
||||
<action android:name="android.app.action.PROFILE_PROVISIONING_COMPLETE"/>
|
||||
<action android:name="android.app.action.CHECK_POLICY_COMPLIANCE"/>
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
@@ -417,11 +417,22 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) {
|
||||
composable<AddApnSetting> { AddApnSettingScreen(it.arguments?.getParcelable("setting"), ::navigateUp) }
|
||||
|
||||
composable<WorkProfile> { WorkProfileScreen(::navigateUp, ::navigate) }
|
||||
composable<OrganizationOwnedProfile> { OrganizationOwnedProfileScreen(::navigateUp) }
|
||||
composable<CreateWorkProfile> { CreateWorkProfileScreen(::navigateUp) }
|
||||
composable<SuspendPersonalApp> { SuspendPersonalAppScreen(::navigateUp) }
|
||||
composable<CrossProfileIntentFilter> { CrossProfileIntentFilterScreen(::navigateUp) }
|
||||
composable<DeleteWorkProfile> { DeleteWorkProfileScreen(::navigateUp) }
|
||||
composable<OrganizationOwnedProfile> {
|
||||
OrganizationOwnedProfileScreen(vm::activateOrgProfileByShizuku, ::navigateUp)
|
||||
}
|
||||
composable<CreateWorkProfile> {
|
||||
CreateWorkProfileScreen(vm::createWorkProfile, ::navigateUp)
|
||||
}
|
||||
composable<SuspendPersonalApp> {
|
||||
SuspendPersonalAppScreen(
|
||||
vm::getPersonalAppsSuspendedReason, vm::setPersonalAppsSuspended,
|
||||
vm::getProfileMaxTimeOff, vm::setProfileMaxTimeOff, ::navigateUp
|
||||
)
|
||||
}
|
||||
composable<CrossProfileIntentFilter> {
|
||||
CrossProfileIntentFilterScreen(vm::addCrossProfileIntentFilter, ::navigateUp)
|
||||
}
|
||||
composable<DeleteWorkProfile> { DeleteWorkProfileScreen(vm::wipeData, ::navigateUp) }
|
||||
|
||||
composable<ApplicationsList> {
|
||||
val canSwitchView = (it.toRoute() as ApplicationsList).canSwitchView
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.bintianqi.owndroid
|
||||
|
||||
import android.accounts.Account
|
||||
import android.app.ActivityOptions
|
||||
import android.app.Application
|
||||
import android.app.PendingIntent
|
||||
@@ -35,13 +36,17 @@ import com.bintianqi.owndroid.Privilege.DPM
|
||||
import com.bintianqi.owndroid.dpm.ACTIVATE_DEVICE_OWNER_COMMAND
|
||||
import com.bintianqi.owndroid.dpm.AppStatus
|
||||
import com.bintianqi.owndroid.dpm.CaCertInfo
|
||||
import com.bintianqi.owndroid.dpm.CreateWorkProfileOptions
|
||||
import com.bintianqi.owndroid.dpm.DelegatedAdmin
|
||||
import com.bintianqi.owndroid.dpm.DeviceAdmin
|
||||
import com.bintianqi.owndroid.dpm.FrpPolicyInfo
|
||||
import com.bintianqi.owndroid.dpm.HardwareProperties
|
||||
import com.bintianqi.owndroid.dpm.IntentFilterDirection
|
||||
import com.bintianqi.owndroid.dpm.IntentFilterOptions
|
||||
import com.bintianqi.owndroid.dpm.PendingSystemUpdateInfo
|
||||
import com.bintianqi.owndroid.dpm.SystemOptionsStatus
|
||||
import com.bintianqi.owndroid.dpm.SystemUpdatePolicyInfo
|
||||
import com.bintianqi.owndroid.dpm.activateOrgProfileCommand
|
||||
import com.bintianqi.owndroid.dpm.delegatedScopesList
|
||||
import com.bintianqi.owndroid.dpm.getPackageInstaller
|
||||
import com.bintianqi.owndroid.dpm.handlePrivilegeChange
|
||||
@@ -294,7 +299,7 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
|
||||
}
|
||||
fun setCmPackage(name: String, status: Boolean) {
|
||||
cmPackages.update { list ->
|
||||
if (status) list + getAppInfo(name) else list.dropWhile { it.name == name }
|
||||
if (status) list + getAppInfo(name) else list.filter { it.name != name }
|
||||
}
|
||||
}
|
||||
@RequiresApi(34)
|
||||
@@ -315,7 +320,7 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
|
||||
}
|
||||
fun setPimPackage(name: String, status: Boolean) {
|
||||
pimPackages.update { packages ->
|
||||
if (status) packages + getAppInfo(name) else packages.dropWhile { it.name == name }
|
||||
if (status) packages + getAppInfo(name) else packages.filter { it.name != name }
|
||||
}
|
||||
}
|
||||
fun setPimPolicy(allowAll: Boolean): Boolean {
|
||||
@@ -335,7 +340,7 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
|
||||
}
|
||||
fun setPasPackage(name: String, status: Boolean) {
|
||||
pasPackages.update { packages ->
|
||||
if (status) packages + getAppInfo(name) else packages.dropWhile { it.name == name }
|
||||
if (status) packages + getAppInfo(name) else packages.filter { it.name != name }
|
||||
}
|
||||
}
|
||||
fun setPasPolicy(allowAll: Boolean): Boolean {
|
||||
@@ -1022,6 +1027,81 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
|
||||
false
|
||||
}
|
||||
}
|
||||
fun createWorkProfile(options: CreateWorkProfileOptions): Intent {
|
||||
val intent = Intent(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE)
|
||||
if (VERSION.SDK_INT >= 23) {
|
||||
intent.putExtra(
|
||||
DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME,
|
||||
MyAdminComponent
|
||||
)
|
||||
} else {
|
||||
intent.putExtra(
|
||||
DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME,
|
||||
application.packageName
|
||||
)
|
||||
}
|
||||
if (options.migrateAccount && VERSION.SDK_INT >= 22) {
|
||||
intent.putExtra(
|
||||
DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE,
|
||||
Account(options.accountName, options.accountType)
|
||||
)
|
||||
if (VERSION.SDK_INT >= 26) {
|
||||
intent.putExtra(
|
||||
DevicePolicyManager.EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION,
|
||||
options.keepAccount
|
||||
)
|
||||
}
|
||||
}
|
||||
if (VERSION.SDK_INT >= 24) {
|
||||
intent.putExtra(
|
||||
DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION,
|
||||
options.skipEncrypt
|
||||
)
|
||||
}
|
||||
if (VERSION.SDK_INT >= 33) {
|
||||
intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_ALLOW_OFFLINE, options.offline)
|
||||
}
|
||||
return intent
|
||||
}
|
||||
fun activateOrgProfileByShizuku(callback: (Boolean) -> Unit) {
|
||||
viewModelScope.launch {
|
||||
var succeed = false
|
||||
useShizuku(application) { service ->
|
||||
val result = IUserService.Stub.asInterface(service).execute(activateOrgProfileCommand)
|
||||
succeed = result?.getInt("code", -1) == 0
|
||||
callback(succeed)
|
||||
}
|
||||
if (succeed) Privilege.updateStatus()
|
||||
}
|
||||
}
|
||||
@RequiresApi(30)
|
||||
fun getPersonalAppsSuspendedReason(): Int {
|
||||
return DPM.getPersonalAppsSuspendedReasons(DAR)
|
||||
}
|
||||
@RequiresApi(30)
|
||||
fun setPersonalAppsSuspended(suspended: Boolean) {
|
||||
DPM.setPersonalAppsSuspended(DAR, suspended)
|
||||
}
|
||||
@RequiresApi(30)
|
||||
fun getProfileMaxTimeOff(): Long {
|
||||
return DPM.getManagedProfileMaximumTimeOff(DAR)
|
||||
}
|
||||
@RequiresApi(30)
|
||||
fun setProfileMaxTimeOff(time: Long) {
|
||||
DPM.setManagedProfileMaximumTimeOff(DAR, time)
|
||||
}
|
||||
fun addCrossProfileIntentFilter(options: IntentFilterOptions) {
|
||||
val filter = IntentFilter(options.action)
|
||||
if (options.category.isNotEmpty()) filter.addCategory(options.category)
|
||||
if (options.mimeType.isNotEmpty()) filter.addDataType(options.mimeType)
|
||||
val flags = when(options.direction) {
|
||||
IntentFilterDirection.ToManaged -> DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED
|
||||
IntentFilterDirection.ToParent -> DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT
|
||||
IntentFilterDirection.Both -> DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED or
|
||||
DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT
|
||||
}
|
||||
DPM.addCrossProfileIntentFilter(DAR, filter, flags)
|
||||
}
|
||||
}
|
||||
|
||||
data class ThemeSettings(
|
||||
|
||||
@@ -57,7 +57,9 @@ fun useShizuku(context: Context, action: (IBinder?) -> Unit) {
|
||||
} else {
|
||||
Sui.init(context.packageName)
|
||||
fun requestPermissionResultListener(requestCode: Int, grantResult: Int) {
|
||||
if(grantResult != PackageManager.PERMISSION_GRANTED) {
|
||||
if (grantResult == PackageManager.PERMISSION_GRANTED) {
|
||||
Shizuku.bindUserService(getShizukuArgs(context), connection)
|
||||
} else {
|
||||
context.popToast(R.string.permission_denied)
|
||||
}
|
||||
Shizuku.removeRequestPermissionResultListener(::requestPermissionResultListener)
|
||||
|
||||
@@ -273,6 +273,7 @@ fun ApplicationDetailsScreen(
|
||||
)
|
||||
if(VERSION.SDK_INT >= 28) FunctionItem(R.string.clear_app_storage, icon = R.drawable.mop_fill0) { dialog = 1 }
|
||||
FunctionItem(R.string.uninstall, icon = R.drawable.delete_fill0) { dialog = 2 }
|
||||
Spacer(Modifier.height(40.dp))
|
||||
}
|
||||
if(dialog == 1 && VERSION.SDK_INT >= 28)
|
||||
ClearAppStorageDialog(packageName, vm::clearAppData) { dialog = 0 }
|
||||
@@ -604,6 +605,7 @@ fun CredentialManagerPolicyScreen(
|
||||
) {
|
||||
Text(stringResource(R.string.apply))
|
||||
}
|
||||
Spacer(Modifier.height(40.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -658,6 +660,7 @@ fun PermittedAsAndImPackages(
|
||||
}
|
||||
Spacer(Modifier.height(10.dp))
|
||||
Notes(note, HorizontalPadding)
|
||||
Spacer(Modifier.height(40.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -767,6 +770,7 @@ fun PackageFunctionScreen(
|
||||
Text(stringResource(R.string.add))
|
||||
}
|
||||
if (notes != null) Notes(notes, HorizontalPadding)
|
||||
Spacer(Modifier.height(40.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1262,6 +1262,7 @@ private fun LockTaskPackages(
|
||||
Text(stringResource(R.string.add))
|
||||
}
|
||||
Notes(R.string.info_lock_task_packages)
|
||||
Spacer(Modifier.height(40.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,9 @@
|
||||
package com.bintianqi.owndroid.dpm
|
||||
|
||||
import android.accounts.Account
|
||||
import android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE
|
||||
import android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE
|
||||
import android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ALLOW_OFFLINE
|
||||
import android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME
|
||||
import android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME
|
||||
import android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION
|
||||
import android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION
|
||||
import android.app.admin.DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT
|
||||
import android.app.admin.DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED
|
||||
import android.app.admin.DevicePolicyManager.PERSONAL_APPS_NOT_SUSPENDED
|
||||
import android.app.admin.DevicePolicyManager.PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT
|
||||
import android.app.admin.DevicePolicyManager
|
||||
import android.app.admin.DevicePolicyManager.WIPE_EUICC
|
||||
import android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Binder
|
||||
import android.os.Build.VERSION
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
@@ -24,6 +11,7 @@ import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
@@ -33,8 +21,13 @@ import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||
import androidx.compose.material3.MaterialTheme.colorScheme
|
||||
import androidx.compose.material3.MaterialTheme.typography
|
||||
import androidx.compose.material3.MenuAnchorType
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
@@ -45,6 +38,7 @@ import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
@@ -55,18 +49,19 @@ import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.bintianqi.owndroid.IUserService
|
||||
import com.bintianqi.owndroid.MyAdminComponent
|
||||
import com.bintianqi.owndroid.HorizontalPadding
|
||||
import com.bintianqi.owndroid.Privilege
|
||||
import com.bintianqi.owndroid.R
|
||||
import com.bintianqi.owndroid.popToast
|
||||
import com.bintianqi.owndroid.showOperationResultToast
|
||||
import com.bintianqi.owndroid.ui.CheckBoxItem
|
||||
import com.bintianqi.owndroid.ui.CircularProgressDialog
|
||||
import com.bintianqi.owndroid.ui.ExpandExposedTextFieldIcon
|
||||
import com.bintianqi.owndroid.ui.FullWidthCheckBoxItem
|
||||
import com.bintianqi.owndroid.ui.FunctionItem
|
||||
import com.bintianqi.owndroid.ui.MyScaffold
|
||||
import com.bintianqi.owndroid.ui.Notes
|
||||
import com.bintianqi.owndroid.ui.SwitchItem
|
||||
import com.bintianqi.owndroid.useShizuku
|
||||
import com.bintianqi.owndroid.yesOrNo
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable object WorkProfile
|
||||
@@ -86,22 +81,28 @@ fun WorkProfileScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
|
||||
}
|
||||
}
|
||||
|
||||
data class CreateWorkProfileOptions(
|
||||
val skipEncrypt: Boolean, val offline: Boolean, val migrateAccount: Boolean,
|
||||
val accountName: String, val accountType: String, val keepAccount: Boolean
|
||||
)
|
||||
|
||||
@Serializable object CreateWorkProfile
|
||||
|
||||
@Composable
|
||||
fun CreateWorkProfileScreen(onNavigateUp: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
fun CreateWorkProfileScreen(
|
||||
createIntent: (CreateWorkProfileOptions) -> Intent, onNavigateUp: () -> Unit
|
||||
) {
|
||||
val focusMgr = LocalFocusManager.current
|
||||
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { }
|
||||
MyScaffold(R.string.create_work_profile, onNavigateUp) {
|
||||
MyScaffold(R.string.create_work_profile, onNavigateUp, 0.dp) {
|
||||
var skipEncrypt by remember { mutableStateOf(false) }
|
||||
var offlineProvisioning by remember { mutableStateOf(true) }
|
||||
var migrateAccount by remember { mutableStateOf(false) }
|
||||
var migrateAccountName by remember { mutableStateOf("") }
|
||||
var migrateAccountType by remember { mutableStateOf("") }
|
||||
var keepAccount by remember { mutableStateOf(true) }
|
||||
if(VERSION.SDK_INT >= 22) {
|
||||
CheckBoxItem(R.string.migrate_account, migrateAccount) { migrateAccount = it }
|
||||
if (VERSION.SDK_INT >= 22) {
|
||||
FullWidthCheckBoxItem(R.string.migrate_account, migrateAccount) { migrateAccount = it }
|
||||
AnimatedVisibility(migrateAccount) {
|
||||
val fr = FocusRequester()
|
||||
Column(modifier = Modifier.padding(start = 10.dp)) {
|
||||
@@ -110,47 +111,40 @@ fun CreateWorkProfileScreen(onNavigateUp: () -> Unit) {
|
||||
label = { Text(stringResource(R.string.account_name)) },
|
||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
|
||||
keyboardActions = KeyboardActions { fr.requestFocus() },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = HorizontalPadding)
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = migrateAccountType, onValueChange = { migrateAccountType = it },
|
||||
label = { Text(stringResource(R.string.account_type)) },
|
||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||
keyboardActions = KeyboardActions { focusMgr.clearFocus() },
|
||||
modifier = Modifier.fillMaxWidth().focusRequester(fr)
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = HorizontalPadding)
|
||||
.focusRequester(fr)
|
||||
)
|
||||
if(VERSION.SDK_INT >= 26) {
|
||||
CheckBoxItem(R.string.keep_account, keepAccount) { keepAccount = it }
|
||||
FullWidthCheckBoxItem(R.string.keep_account, keepAccount) { keepAccount = it }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(VERSION.SDK_INT >= 24) CheckBoxItem(R.string.skip_encryption, skipEncrypt) { skipEncrypt = it }
|
||||
if(VERSION.SDK_INT >= 33) CheckBoxItem(R.string.offline_provisioning, offlineProvisioning) { offlineProvisioning = it }
|
||||
if (VERSION.SDK_INT >= 24) FullWidthCheckBoxItem(
|
||||
R.string.skip_encryption, skipEncrypt
|
||||
) { skipEncrypt = it }
|
||||
if (VERSION.SDK_INT >= 33) FullWidthCheckBoxItem(
|
||||
R.string.offline_provisioning, offlineProvisioning
|
||||
) { offlineProvisioning = it }
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
Button(
|
||||
onClick = {
|
||||
try {
|
||||
val intent = Intent(ACTION_PROVISION_MANAGED_PROFILE)
|
||||
if(VERSION.SDK_INT >= 23) {
|
||||
intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, MyAdminComponent)
|
||||
} else {
|
||||
intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, context.packageName)
|
||||
}
|
||||
if(migrateAccount && VERSION.SDK_INT >= 22) {
|
||||
intent.putExtra(EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE, Account(migrateAccountName, migrateAccountType))
|
||||
if(VERSION.SDK_INT >= 26) {
|
||||
intent.putExtra(EXTRA_PROVISIONING_KEEP_ACCOUNT_ON_MIGRATION, keepAccount)
|
||||
}
|
||||
}
|
||||
if(VERSION.SDK_INT >= 24) { intent.putExtra(EXTRA_PROVISIONING_SKIP_ENCRYPTION, skipEncrypt) }
|
||||
if(VERSION.SDK_INT >= 33) { intent.putExtra(EXTRA_PROVISIONING_ALLOW_OFFLINE, offlineProvisioning) }
|
||||
launcher.launch(intent)
|
||||
} catch(_: ActivityNotFoundException) {
|
||||
context.popToast(R.string.unsupported)
|
||||
}
|
||||
val intent = createIntent(CreateWorkProfileOptions(
|
||||
skipEncrypt, offlineProvisioning, migrateAccount, migrateAccountName,
|
||||
migrateAccountType, keepAccount
|
||||
))
|
||||
launcher.launch(intent)
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = HorizontalPadding)
|
||||
) {
|
||||
Text(stringResource(R.string.create))
|
||||
}
|
||||
@@ -161,18 +155,19 @@ fun CreateWorkProfileScreen(onNavigateUp: () -> Unit) {
|
||||
|
||||
@RequiresApi(30)
|
||||
@Composable
|
||||
fun OrganizationOwnedProfileScreen(onNavigateUp: () -> Unit) {
|
||||
fun OrganizationOwnedProfileScreen(
|
||||
onActivate: ((Boolean) -> Unit) -> Unit, onNavigateUp: () -> Unit
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
var activating by remember { mutableStateOf(false) }
|
||||
var dialog by remember { mutableStateOf(false) }
|
||||
MyScaffold(R.string.org_owned_work_profile, onNavigateUp) {
|
||||
Button({
|
||||
useShizuku(context) { service ->
|
||||
val result = IUserService.Stub.asInterface(service).execute(activateOrgProfileCommand)
|
||||
if (result?.getInt("code", -1) == 0) {
|
||||
context.showOperationResultToast(true)
|
||||
} else {
|
||||
context.showOperationResultToast(false)
|
||||
}
|
||||
activating = true
|
||||
onActivate {
|
||||
activating = false
|
||||
context.showOperationResultToast(it)
|
||||
if (it) onNavigateUp()
|
||||
}
|
||||
}) {
|
||||
Text(stringResource(R.string.shizuku))
|
||||
@@ -189,6 +184,7 @@ fun OrganizationOwnedProfileScreen(onNavigateUp: () -> Unit) {
|
||||
},
|
||||
onDismissRequest = { dialog = false }
|
||||
)
|
||||
if (activating) CircularProgressDialog { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,41 +195,46 @@ val activateOrgProfileCommand = "dpm mark-profile-owner-on-organization-owned-de
|
||||
|
||||
@RequiresApi(30)
|
||||
@Composable
|
||||
fun SuspendPersonalAppScreen(onNavigateUp: () -> Unit) {
|
||||
fun SuspendPersonalAppScreen(
|
||||
getSuspendedReasons: () -> Int, setSuspended: (Boolean) -> Unit, getMaxTime: () -> Long,
|
||||
setMaxTime: (Long) -> Unit, onNavigateUp: () -> Unit
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val focusMgr = LocalFocusManager.current
|
||||
var suspend by remember { mutableStateOf(Privilege.DPM.getPersonalAppsSuspendedReasons(Privilege.DAR) != PERSONAL_APPS_NOT_SUSPENDED) }
|
||||
var reason by remember { mutableIntStateOf(DevicePolicyManager.PERSONAL_APPS_NOT_SUSPENDED) }
|
||||
var time by remember { mutableStateOf("") }
|
||||
LaunchedEffect(Unit) {
|
||||
reason = getSuspendedReasons()
|
||||
time = getMaxTime().toString()
|
||||
}
|
||||
MyScaffold(R.string.suspend_personal_app, onNavigateUp) {
|
||||
SwitchItem(R.string.suspend_personal_app, state = suspend,
|
||||
SwitchItem(R.string.suspend_personal_app, state = reason != 0,
|
||||
onCheckedChange = {
|
||||
Privilege.DPM.setPersonalAppsSuspended(Privilege.DAR, it)
|
||||
suspend = Privilege.DPM.getPersonalAppsSuspendedReasons(Privilege.DAR) != PERSONAL_APPS_NOT_SUSPENDED
|
||||
setSuspended(it)
|
||||
reason = if (it) DevicePolicyManager.PERSONAL_APPS_SUSPENDED_EXPLICITLY
|
||||
else DevicePolicyManager.PERSONAL_APPS_NOT_SUSPENDED
|
||||
}, padding = false
|
||||
)
|
||||
var time by remember { mutableStateOf("") }
|
||||
time = Privilege.DPM.getManagedProfileMaximumTimeOff(Privilege.DAR).toString()
|
||||
Spacer(Modifier.padding(vertical = 10.dp))
|
||||
Text(text = stringResource(R.string.profile_max_time_off), style = typography.titleLarge)
|
||||
Text(text = stringResource(R.string.profile_max_time_out_desc))
|
||||
Text(
|
||||
text = stringResource(
|
||||
R.string.personal_app_suspended_because_timeout,
|
||||
Privilege.DPM.getPersonalAppsSuspendedReasons(Privilege.DAR) == PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT
|
||||
)
|
||||
)
|
||||
Text(stringResource(
|
||||
R.string.personal_app_suspended_because_timeout,
|
||||
stringResource((reason == DevicePolicyManager.PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT).yesOrNo)
|
||||
))
|
||||
OutlinedTextField(
|
||||
value = time, onValueChange = { time=it }, modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp),
|
||||
label = { Text(stringResource(R.string.time_unit_ms)) },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
|
||||
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus() })
|
||||
)
|
||||
Text(text = stringResource(R.string.cannot_less_than_72_hours))
|
||||
Button(
|
||||
onClick = {
|
||||
Privilege.DPM.setManagedProfileMaximumTimeOff(Privilege.DAR, time.toLong())
|
||||
setMaxTime(time.toLong())
|
||||
context.showOperationResultToast(true)
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
enabled = time.toLongOrNull() != null
|
||||
) {
|
||||
Text(stringResource(R.string.apply))
|
||||
}
|
||||
@@ -241,14 +242,33 @@ fun SuspendPersonalAppScreen(onNavigateUp: () -> Unit) {
|
||||
}
|
||||
}
|
||||
|
||||
data class IntentFilterOptions(
|
||||
val action: String, val category: String, val mimeType: String,
|
||||
val direction: IntentFilterDirection
|
||||
)
|
||||
enum class IntentFilterDirection(val text: Int) {
|
||||
ToParent(R.string.work_to_personal), ToManaged(R.string.personal_to_work),
|
||||
Both(R.string.both_direction)
|
||||
}
|
||||
|
||||
@Serializable object CrossProfileIntentFilter
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun CrossProfileIntentFilterScreen(onNavigateUp: () -> Unit) {
|
||||
fun CrossProfileIntentFilterScreen(
|
||||
addFilter: (IntentFilterOptions) -> Unit,
|
||||
onNavigateUp: () -> Unit
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val focusMgr = LocalFocusManager.current
|
||||
var action by remember { mutableStateOf("") }
|
||||
var customCategory by remember { mutableStateOf(false) }
|
||||
var category by remember { mutableStateOf("") }
|
||||
var customMimeType by remember { mutableStateOf(false) }
|
||||
var mimeType by remember { mutableStateOf("") }
|
||||
var dropdown by remember { mutableStateOf(false) }
|
||||
var direction by remember { mutableStateOf(IntentFilterDirection.Both) }
|
||||
MyScaffold(R.string.intent_filter, onNavigateUp) {
|
||||
var action by remember { mutableStateOf("") }
|
||||
OutlinedTextField(
|
||||
value = action, onValueChange = { action = it },
|
||||
label = { Text("Action") },
|
||||
@@ -256,32 +276,61 @@ fun CrossProfileIntentFilterScreen(onNavigateUp: () -> Unit) {
|
||||
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus() }),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
Button(
|
||||
onClick = {
|
||||
Privilege.DPM.addCrossProfileIntentFilter(Privilege.DAR, IntentFilter(action), FLAG_PARENT_CAN_ACCESS_MANAGED)
|
||||
context.showOperationResultToast(true)
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(stringResource(R.string.add_intent_filter_work_to_personal))
|
||||
Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||
Checkbox(customCategory, {
|
||||
customCategory = it
|
||||
category = ""
|
||||
})
|
||||
OutlinedTextField(
|
||||
category, { category = it }, Modifier.fillMaxWidth(),
|
||||
label = { Text("Category") }, enabled = customCategory
|
||||
)
|
||||
}
|
||||
Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||
Checkbox(customMimeType, {
|
||||
customMimeType = it
|
||||
mimeType = ""
|
||||
})
|
||||
OutlinedTextField(
|
||||
mimeType, { mimeType = it }, Modifier.fillMaxWidth(),
|
||||
label = { Text("MIME type") }, enabled = customMimeType
|
||||
)
|
||||
}
|
||||
ExposedDropdownMenuBox(dropdown, { dropdown = it }, Modifier.padding(vertical = 5.dp)) {
|
||||
OutlinedTextField(
|
||||
stringResource(direction.text), {},
|
||||
Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth(),
|
||||
label = { Text(stringResource(R.string.direction)) }, readOnly = true,
|
||||
trailingIcon = { ExpandExposedTextFieldIcon(dropdown) }
|
||||
)
|
||||
ExposedDropdownMenu(dropdown, { dropdown = false }) {
|
||||
IntentFilterDirection.entries.forEach {
|
||||
DropdownMenuItem({ Text(stringResource(it.text)) }, {
|
||||
direction = it
|
||||
dropdown = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
Button(
|
||||
onClick = {
|
||||
Privilege.DPM.addCrossProfileIntentFilter(Privilege.DAR, IntentFilter(action), FLAG_MANAGED_CAN_ACCESS_PARENT)
|
||||
{
|
||||
addFilter(IntentFilterOptions(
|
||||
action, category, mimeType, direction
|
||||
))
|
||||
context.showOperationResultToast(true)
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
Modifier.fillMaxWidth(),
|
||||
enabled = action.isNotBlank() && (!customCategory || category.isNotBlank()) &&
|
||||
(!customMimeType || mimeType.isNotBlank())
|
||||
) {
|
||||
Text(stringResource(R.string.add_intent_filter_personal_to_work))
|
||||
Text(stringResource(R.string.add))
|
||||
}
|
||||
Spacer(Modifier.padding(vertical = 2.dp))
|
||||
Button(
|
||||
onClick = {
|
||||
Privilege.DPM.clearCrossProfileIntentFilters(Privilege.DAR)
|
||||
context.showOperationResultToast(true)
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier.fillMaxWidth().padding(vertical = 6.dp)
|
||||
) {
|
||||
Text(stringResource(R.string.clear_cross_profile_filters))
|
||||
}
|
||||
@@ -292,28 +341,34 @@ fun CrossProfileIntentFilterScreen(onNavigateUp: () -> Unit) {
|
||||
@Serializable object DeleteWorkProfile
|
||||
|
||||
@Composable
|
||||
fun DeleteWorkProfileScreen(onNavigateUp: () -> Unit) {
|
||||
fun DeleteWorkProfileScreen(
|
||||
deleteProfile: (Boolean, Int, String) -> Unit, onNavigateUp: () -> Unit
|
||||
) {
|
||||
val focusMgr = LocalFocusManager.current
|
||||
var flag by remember { mutableIntStateOf(0) }
|
||||
var flags by remember { mutableIntStateOf(0) }
|
||||
var warning by remember { mutableStateOf(false) }
|
||||
var silent by remember { mutableStateOf(false) }
|
||||
var reason by remember { mutableStateOf("") }
|
||||
MyScaffold(R.string.delete_work_profile, onNavigateUp) {
|
||||
CheckBoxItem(R.string.wipe_external_storage, flag and WIPE_EXTERNAL_STORAGE != 0) { flag = flag xor WIPE_EXTERNAL_STORAGE }
|
||||
if(VERSION.SDK_INT >= 28) CheckBoxItem(R.string.wipe_euicc, flag and WIPE_EUICC != 0) { flag = flag xor WIPE_EUICC }
|
||||
CheckBoxItem(R.string.wipe_silently, silent) { silent = it }
|
||||
AnimatedVisibility(!silent && VERSION.SDK_INT >= 28) {
|
||||
OutlinedTextField(
|
||||
value = reason, onValueChange = { reason = it },
|
||||
label = { Text(stringResource(R.string.reason)) },
|
||||
modifier = Modifier.fillMaxWidth().padding(vertical = 3.dp)
|
||||
)
|
||||
CheckBoxItem(R.string.wipe_external_storage, flags and WIPE_EXTERNAL_STORAGE != 0) {
|
||||
flags = flags xor WIPE_EXTERNAL_STORAGE
|
||||
}
|
||||
if(VERSION.SDK_INT >= 28) CheckBoxItem(R.string.wipe_euicc, flags and WIPE_EUICC != 0) {
|
||||
flags = flags xor WIPE_EUICC
|
||||
}
|
||||
CheckBoxItem(R.string.wipe_silently, flags and DevicePolicyManager.WIPE_SILENTLY != 0) {
|
||||
flags = flags xor DevicePolicyManager.WIPE_SILENTLY
|
||||
reason = ""
|
||||
}
|
||||
if (VERSION.SDK_INT >= 28) OutlinedTextField(
|
||||
value = reason, onValueChange = { reason = it },
|
||||
label = { Text(stringResource(R.string.reason)) },
|
||||
enabled = flags and DevicePolicyManager.WIPE_SILENTLY == 0,
|
||||
modifier = Modifier.fillMaxWidth().padding(vertical = 3.dp)
|
||||
)
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
Button(
|
||||
onClick = {
|
||||
focusMgr.clearFocus()
|
||||
silent = reason == ""
|
||||
warning = true
|
||||
},
|
||||
colors = ButtonDefaults.buttonColors(containerColor = colorScheme.error, contentColor = colorScheme.onError),
|
||||
@@ -322,8 +377,7 @@ fun DeleteWorkProfileScreen(onNavigateUp: () -> Unit) {
|
||||
Text(stringResource(R.string.delete))
|
||||
}
|
||||
}
|
||||
if(warning) {
|
||||
LaunchedEffect(Unit) { silent = reason == "" }
|
||||
if (warning) {
|
||||
AlertDialog(
|
||||
title = {
|
||||
Text(text = stringResource(R.string.warning), color = colorScheme.error)
|
||||
@@ -335,11 +389,7 @@ fun DeleteWorkProfileScreen(onNavigateUp: () -> Unit) {
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
if(VERSION.SDK_INT >= 28 && !silent) {
|
||||
Privilege.DPM.wipeData(flag, reason)
|
||||
} else {
|
||||
Privilege.DPM.wipeData(flag)
|
||||
}
|
||||
deleteProfile(false, flags, reason)
|
||||
},
|
||||
colors = ButtonDefaults.textButtonColors(contentColor = colorScheme.error)
|
||||
) {
|
||||
|
||||
@@ -75,7 +75,6 @@
|
||||
<string name="profile_owner">Владелец профиля</string>
|
||||
<string name="device_owner">Владелец устройства</string>
|
||||
<string name="delegated_admins">Делегированные администраторы</string>
|
||||
<string name="delegated_scope">делегированные возможности</string>
|
||||
<string name="manage_application_restrictions">Управление ограничениями для приложений</string>
|
||||
<string name="manage_certificates">Управление сертификатами</string>
|
||||
<string name="select_keychain_certificates">Выберите сертификат связки ключей</string>
|
||||
@@ -101,7 +100,6 @@
|
||||
<string name="disable_account_management">Отключить управление аккаунтами</string>
|
||||
<string name="account_type">Тип аккаунта</string>
|
||||
<string name="transfer_ownership">Передача прав владения</string>
|
||||
<string name="target_component_name">Имя целевого компонента</string>
|
||||
<string name="lock_screen_info">Информация на экране блокировки</string>
|
||||
<string name="support_messages">Сообщение поддержки</string>
|
||||
<string name="short_support_msg">Краткое сообщение</string>
|
||||
@@ -212,8 +210,6 @@
|
||||
<string name="update_received_time">Время получения обновления: %1$s</string>
|
||||
<string name="install_system_update">Установить системное обновление</string>
|
||||
<string name="select_ota_package" tools:ignore="TypographyEllipsis">Выберите OTA-пакет...</string>
|
||||
<string name="start_install_system_update">Начать установку системного обновления</string>
|
||||
<string name="install_system_update_failed">Установка системного обновления не удалась: </string>
|
||||
<string name="battery_low">Низкий заряд батареи</string>
|
||||
<string name="update_file_invalid">Файл обновления недействителен</string>
|
||||
<string name="incorrect_os_ver">Неверная версия ОС</string>
|
||||
@@ -339,10 +335,7 @@
|
||||
<string name="profile_max_time_off">Максимальное время отключения</string>
|
||||
<string name="profile_max_time_out_desc">Личные приложения будут приостановлены после закрытия рабочего профиля на указанное время. 0 означает отсутствие ограничения.</string>
|
||||
<string name="personal_app_suspended_because_timeout">Личное приложение приостановлено по причине: %1$s</string>
|
||||
<string name="cannot_less_than_72_hours">Не может быть меньше 72 часов</string>
|
||||
<string name="intent_filter">Фильтр намерений</string>
|
||||
<string name="add_intent_filter_work_to_personal">Добавить (из рабочего в личный)</string>
|
||||
<string name="add_intent_filter_personal_to_work">Добавить (из личного в рабочий)</string>
|
||||
<string name="clear_cross_profile_filters">Очистить все фильтры</string>
|
||||
<string name="org_id">Идентификатор организации</string>
|
||||
<string name="length_6_to_64">Длина должна быть от 6 до 64 символов</string>
|
||||
|
||||
@@ -76,7 +76,6 @@
|
||||
<string name="profile_owner">Profil Sahibi</string>
|
||||
<string name="device_owner">Cihaz Sahibi</string>
|
||||
<string name="delegated_admins">Yetkilendirilmiş Yöneticiler</string>
|
||||
<string name="delegated_scope">Yetkilendirilmiş Kapsam</string>
|
||||
<string name="manage_application_restrictions">Uygulama Kısıtlamalarını Yönet</string>
|
||||
<string name="manage_certificates">Sertifikaları Yönet</string>
|
||||
<string name="select_keychain_certificates">KeyChain Sertifikasını Seç</string>
|
||||
@@ -102,7 +101,6 @@
|
||||
<string name="disable_account_management">Hesap Yönetimini Devre Dışı Bırak</string>
|
||||
<string name="account_type">Hesap Türü</string>
|
||||
<string name="transfer_ownership">Sahipliği Devret</string>
|
||||
<string name="target_component_name">Hedef Bileşen Adı</string>
|
||||
<string name="lock_screen_info">Kilit Ekranı Bilgisi</string>
|
||||
<string name="support_messages">Destek Mesajları</string>
|
||||
<string name="short_support_msg">Kısa Mesaj</string>
|
||||
@@ -243,8 +241,6 @@
|
||||
|
||||
<string name="install_system_update">Sistem Güncellemesini Yükle</string>
|
||||
<string name="select_ota_package" tools:ignore="TypographyEllipsis">OTA paketini seç...</string>
|
||||
<string name="start_install_system_update">Sistem güncellemesini yüklemeye başla</string>
|
||||
<string name="install_system_update_failed">"Sistem güncellemesi yüklenemedi: "</string>
|
||||
<string name="battery_low">Pil seviyesi düşük</string>
|
||||
<string name="update_file_invalid">Güncelleme dosyası geçersiz</string>
|
||||
<string name="incorrect_os_ver">Yanlış işletim sistemi sürümü</string>
|
||||
@@ -365,10 +361,7 @@
|
||||
<string name="profile_max_time_off">Maksimum Kapalı Kalma Süresi</string>
|
||||
<string name="profile_max_time_out_desc">İş profili kapatıldıktan sonra kişisel uygulamalar bu süre boyunca askıya alınacak. 0, sınırsız anlamına gelir.</string>
|
||||
<string name="personal_app_suspended_because_timeout">Kişisel uygulama şu nedenle askıya alındı: %1$s</string>
|
||||
<string name="cannot_less_than_72_hours">72 saatten az olamaz</string>
|
||||
<string name="intent_filter">Niyet Filtresi</string>
|
||||
<string name="add_intent_filter_work_to_personal">Ekle (işten kişisel profile)</string>
|
||||
<string name="add_intent_filter_personal_to_work">Ekle (kişisel profilden işe)</string>
|
||||
<string name="clear_cross_profile_filters">Tüm filtreleri temizle</string>
|
||||
<string name="org_id">Kurum Kimliği</string>
|
||||
<string name="length_6_to_64">Uzunluk 6 ile 64 karakter arasında olmalıdır</string>
|
||||
|
||||
@@ -74,7 +74,6 @@
|
||||
<string name="profile_owner">Profile owner</string>
|
||||
<string name="device_owner">Device owner</string>
|
||||
<string name="delegated_admins">委托管理员</string>
|
||||
<string name="delegated_scope">委托作用域</string>
|
||||
<string name="manage_application_restrictions">管理应用限制</string>
|
||||
<string name="manage_certificates">管理证书</string>
|
||||
<string name="select_keychain_certificates">选择密钥链证书</string>
|
||||
@@ -99,7 +98,6 @@
|
||||
<string name="disable_account_management">禁用账号管理</string>
|
||||
<string name="account_type">账号类型</string>
|
||||
<string name="transfer_ownership">转移所有权</string>
|
||||
<string name="target_component_name">目标组件名</string>
|
||||
<string name="lock_screen_info">锁屏提示信息</string>
|
||||
<string name="support_messages">提供支持的消息</string>
|
||||
<string name="short_support_msg">提供支持的短消息</string>
|
||||
@@ -221,8 +219,6 @@
|
||||
<string name="update_received_time">系统更新接收时间: %1$s</string>
|
||||
<string name="install_system_update">安装系统更新</string>
|
||||
<string name="select_ota_package" tools:ignore="TypographyEllipsis">选择OTA包...</string>
|
||||
<string name="start_install_system_update">开始安装系统更新</string>
|
||||
<string name="install_system_update_failed">安装系统更新失败:</string>
|
||||
<string name="battery_low">电量低</string>
|
||||
<string name="update_file_invalid">OTA包无效</string>
|
||||
<string name="incorrect_os_ver">系统版本错误</string>
|
||||
@@ -343,10 +339,11 @@
|
||||
<string name="profile_max_time_off">资料关闭时间</string>
|
||||
<string name="profile_max_time_out_desc">工作资料处于关闭状态的时间达到该限制后会挂起个人应用,0为无限制</string>
|
||||
<string name="personal_app_suspended_because_timeout">个人应用已经因此挂起:%1$s</string>
|
||||
<string name="cannot_less_than_72_hours">不能少于72小时</string>
|
||||
<string name="intent_filter">Intent过滤器</string>
|
||||
<string name="add_intent_filter_work_to_personal">添加(工作到个人)</string>
|
||||
<string name="add_intent_filter_personal_to_work">添加(个人到工作)</string>
|
||||
<string name="direction">方向</string>
|
||||
<string name="both_direction">双向</string>
|
||||
<string name="work_to_personal">工作到个人</string>
|
||||
<string name="personal_to_work">个人到工作</string>
|
||||
<string name="clear_cross_profile_filters">清除所有过滤器</string>
|
||||
<string name="org_id">组织ID</string>
|
||||
<string name="length_6_to_64">长度应在6~64个字符之间</string>
|
||||
|
||||
@@ -79,7 +79,6 @@
|
||||
<string name="profile_owner">Profile owner</string>
|
||||
<string name="device_owner">Device owner</string>
|
||||
<string name="delegated_admins">Delegated admins</string>
|
||||
<string name="delegated_scope">delegated scope</string>
|
||||
<string name="manage_application_restrictions">Manage application restrictions</string>
|
||||
<string name="manage_certificates">Manage certificates</string>
|
||||
<string name="select_keychain_certificates">Select KeyChain certificate</string>
|
||||
@@ -105,7 +104,6 @@
|
||||
<string name="disable_account_management">Disable account management</string>
|
||||
<string name="account_type">Account type</string>
|
||||
<string name="transfer_ownership">Transfer Ownership</string>
|
||||
<string name="target_component_name">Target component name</string>
|
||||
<string name="lock_screen_info">Lock screen info</string>
|
||||
<string name="support_messages">Support Messages</string>
|
||||
<string name="short_support_msg">Short message</string>
|
||||
@@ -249,8 +247,6 @@
|
||||
|
||||
<string name="install_system_update">Install system update</string>
|
||||
<string name="select_ota_package" tools:ignore="TypographyEllipsis">Select OTA package...</string>
|
||||
<string name="start_install_system_update">Start installing system update</string>
|
||||
<string name="install_system_update_failed">"Install system update failed: "</string>
|
||||
<string name="battery_low">Battery is low</string>
|
||||
<string name="update_file_invalid">Update file is invalid</string>
|
||||
<string name="incorrect_os_ver">Incorrect OS version</string>
|
||||
@@ -374,10 +370,11 @@
|
||||
<string name="profile_max_time_off">Max time off</string>
|
||||
<string name="profile_max_time_out_desc">Personal apps will be suspended after the work profile is closed for this amount of time. 0 means no limit. </string>
|
||||
<string name="personal_app_suspended_because_timeout">Personal app suspended because of this: %1$s</string>
|
||||
<string name="cannot_less_than_72_hours">Cannot less than 72 hours</string>
|
||||
<string name="intent_filter">Intent filter</string>
|
||||
<string name="add_intent_filter_work_to_personal">Add(work to personal)</string>
|
||||
<string name="add_intent_filter_personal_to_work">Add(personal to work)</string>
|
||||
<string name="direction">Direction</string>
|
||||
<string name="both_direction">Both direction</string>
|
||||
<string name="work_to_personal">Work to personal</string>
|
||||
<string name="personal_to_work">Personal to work</string>
|
||||
<string name="clear_cross_profile_filters">Clear all filters</string>
|
||||
<string name="org_id">Organization ID</string>
|
||||
<string name="length_6_to_64">The length should be between 6~64 characters</string>
|
||||
|
||||
Reference in New Issue
Block a user