mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-23 11:05:59 +00:00
Secondary user list
Fix crash in User operation when UID/serial number is empty Logout current user in secondary user More user info
This commit is contained in:
@@ -14,6 +14,7 @@ import android.widget.Toast
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.annotation.StringRes
|
||||
import com.bintianqi.owndroid.dpm.addDeviceAdmin
|
||||
import com.bintianqi.owndroid.dpm.createManagedProfile
|
||||
@@ -22,6 +23,9 @@ import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.time.Instant
|
||||
import java.time.ZoneId
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.Locale
|
||||
|
||||
lateinit var getFile: ActivityResultLauncher<Intent>
|
||||
@@ -123,7 +127,12 @@ fun formatFileSize(bytes: Long): String {
|
||||
}
|
||||
}
|
||||
|
||||
@StringRes
|
||||
fun Boolean.yesOrNo(): Int {
|
||||
return if(this) R.string.yes else R.string.no
|
||||
val Boolean.yesOrNo
|
||||
@StringRes get() = if(this) R.string.yes else R.string.no
|
||||
|
||||
@RequiresApi(26)
|
||||
fun parseTimestamp(timestamp: Long): String {
|
||||
val instant = Instant.ofEpochMilli(timestamp)
|
||||
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault())
|
||||
return formatter.format(instant)
|
||||
}
|
||||
|
||||
@@ -283,10 +283,10 @@ private fun PasswordInfo() {
|
||||
CardItem(R.string.current_password_complexity, passwordComplexity[dpm.passwordComplexity] ?: R.string.unknown)
|
||||
}
|
||||
if(deviceOwner || profileOwner) {
|
||||
CardItem(R.string.password_sufficient, dpm.isActivePasswordSufficient.yesOrNo())
|
||||
CardItem(R.string.password_sufficient, dpm.isActivePasswordSufficient.yesOrNo)
|
||||
}
|
||||
if(VERSION.SDK_INT >= 28 && profileOwner && dpm.isManagedProfile(receiver)) {
|
||||
CardItem(R.string.unified_password, dpm.isUsingUnifiedPassword(receiver).yesOrNo())
|
||||
CardItem(R.string.unified_password, dpm.isUsingUnifiedPassword(receiver).yesOrNo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -496,7 +496,7 @@ fun DeviceInfo() {
|
||||
Text(text = stringResource(R.string.device_info), style = typography.headlineLarge)
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
if(VERSION.SDK_INT>=34 && (context.isDeviceOwner || dpm.isOrgProfile(receiver))) {
|
||||
CardItem(R.string.financed_device, dpm.isDeviceFinanced.yesOrNo())
|
||||
CardItem(R.string.financed_device, dpm.isDeviceFinanced.yesOrNo)
|
||||
}
|
||||
if(VERSION.SDK_INT >= 33) {
|
||||
val dpmRole = dpm.devicePolicyManagementRoleHolderPackage
|
||||
@@ -511,10 +511,10 @@ fun DeviceInfo() {
|
||||
if(VERSION.SDK_INT >= 24) { encryptionStatus[DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER] = R.string.es_active_per_user }
|
||||
CardItem(R.string.encryption_status, encryptionStatus[dpm.storageEncryptionStatus] ?: R.string.unknown)
|
||||
if(VERSION.SDK_INT >= 28) {
|
||||
CardItem(R.string.support_device_id_attestation, dpm.isDeviceIdAttestationSupported.yesOrNo()) { dialog = 1 }
|
||||
CardItem(R.string.support_device_id_attestation, dpm.isDeviceIdAttestationSupported.yesOrNo) { dialog = 1 }
|
||||
}
|
||||
if (VERSION.SDK_INT >= 30) {
|
||||
CardItem(R.string.support_unique_device_attestation, dpm.isUniqueDeviceAttestationSupported.yesOrNo()) { dialog = 2 }
|
||||
CardItem(R.string.support_unique_device_attestation, dpm.isUniqueDeviceAttestationSupported.yesOrNo) { dialog = 2 }
|
||||
}
|
||||
val adminList = dpm.activeAdmins
|
||||
if(adminList != null) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import android.os.UserHandle
|
||||
import android.os.UserManager
|
||||
import android.provider.MediaStore
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.Image
|
||||
@@ -33,6 +34,7 @@ import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.Icon
|
||||
@@ -41,10 +43,12 @@ import androidx.compose.material3.MaterialTheme.typography
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
@@ -68,6 +72,7 @@ import androidx.navigation.compose.rememberNavController
|
||||
import com.bintianqi.owndroid.R
|
||||
import com.bintianqi.owndroid.fileUriFlow
|
||||
import com.bintianqi.owndroid.getFile
|
||||
import com.bintianqi.owndroid.parseTimestamp
|
||||
import com.bintianqi.owndroid.toggle
|
||||
import com.bintianqi.owndroid.ui.Animations
|
||||
import com.bintianqi.owndroid.ui.CardItem
|
||||
@@ -121,8 +126,12 @@ fun UserManage(navCtrl: NavHostController) {
|
||||
@Composable
|
||||
private fun Home(navCtrl: NavHostController,scrollState: ScrollState) {
|
||||
val context = LocalContext.current
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val deviceOwner = context.isDeviceOwner
|
||||
val profileOwner = context.isProfileOwner
|
||||
//var logoutDialog by remember { mutableStateOf(false) }
|
||||
var dialog by remember { mutableIntStateOf(0) }
|
||||
Column(modifier = Modifier.fillMaxSize().verticalScroll(scrollState)) {
|
||||
Text(
|
||||
text = stringResource(R.string.user_manager),
|
||||
@@ -131,6 +140,7 @@ private fun Home(navCtrl: NavHostController,scrollState: ScrollState) {
|
||||
)
|
||||
SubPageItem(R.string.user_info, "", R.drawable.person_fill0) { navCtrl.navigate("UserInfo") }
|
||||
if(deviceOwner && VERSION.SDK_INT >= 28) {
|
||||
SubPageItem(R.string.secondary_users, "", R.drawable.list_fill0) { dialog = 1 }
|
||||
SubPageItem(R.string.options, "", R.drawable.tune_fill0) { navCtrl.navigate("Options") }
|
||||
}
|
||||
if(deviceOwner) {
|
||||
@@ -139,6 +149,9 @@ private fun Home(navCtrl: NavHostController,scrollState: ScrollState) {
|
||||
if(VERSION.SDK_INT >= 24 && deviceOwner) {
|
||||
SubPageItem(R.string.create_user, "", R.drawable.person_add_fill0) { navCtrl.navigate("CreateUser") }
|
||||
}
|
||||
if(VERSION.SDK_INT >= 28 && profileOwner && dpm.isAffiliatedUser) {
|
||||
SubPageItem(R.string.logout_current_user, "", R.drawable.logout_fill0) { dialog = 2 }
|
||||
}
|
||||
if(deviceOwner || profileOwner) {
|
||||
SubPageItem(R.string.edit_username, "", R.drawable.edit_fill0) { navCtrl.navigate("EditUsername") }
|
||||
}
|
||||
@@ -154,6 +167,40 @@ private fun Home(navCtrl: NavHostController,scrollState: ScrollState) {
|
||||
Spacer(Modifier.padding(vertical = 30.dp))
|
||||
LaunchedEffect(Unit) { fileUriFlow.value = Uri.parse("") }
|
||||
}
|
||||
if(dialog != 0 && VERSION.SDK_INT >= 28) AlertDialog(
|
||||
title = { Text(stringResource(if(dialog == 1) R.string.secondary_users else R.string.logout_current_user)) },
|
||||
text = {
|
||||
if(dialog == 1) {
|
||||
val um = context.getSystemService(Context.USER_SERVICE) as UserManager
|
||||
val list = dpm.getSecondaryUsers(receiver)
|
||||
Column {
|
||||
Text("(" + stringResource(R.string.serial_number) + ")")
|
||||
list.forEach {
|
||||
Text(um.getSerialNumberForUser(it).toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
if(dialog == 2) {
|
||||
val result = dpm.logoutUser(receiver)
|
||||
Toast.makeText(context, userOperationResultCode(result), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
dialog = 0
|
||||
}
|
||||
) {
|
||||
Text(stringResource(R.string.confirm))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
if(dialog != 1) TextButton(onClick = { dialog = 0 }) {
|
||||
Text(stringResource(R.string.cancel))
|
||||
}
|
||||
},
|
||||
onDismissRequest = { dialog = 0 }
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -174,25 +221,39 @@ private fun CurrentUserInfo() {
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
|
||||
val user = Process.myUserHandle()
|
||||
var infoDialog by remember { mutableIntStateOf(0) }
|
||||
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) {
|
||||
Spacer(Modifier.padding(vertical = 10.dp))
|
||||
Text(text = stringResource(R.string.user_info), style = typography.headlineLarge)
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
if(VERSION.SDK_INT >= 24) CardItem(R.string.support_multiuser, UserManager.supportsMultipleUsers().yesOrNo())
|
||||
if(VERSION.SDK_INT >= 23) CardItem(R.string.system_user, userManager.isSystemUser.yesOrNo())
|
||||
if(VERSION.SDK_INT >= 34) CardItem(R.string.admin_user, userManager.isAdminUser.yesOrNo())
|
||||
if(VERSION.SDK_INT >= 31) CardItem(R.string.headless_system_user, UserManager.isHeadlessSystemUserMode().yesOrNo())
|
||||
if(VERSION.SDK_INT >= 24) CardItem(R.string.support_multiuser, UserManager.supportsMultipleUsers().yesOrNo)
|
||||
if(VERSION.SDK_INT >= 31) CardItem(R.string.headless_system_user_mode, UserManager.isHeadlessSystemUserMode().yesOrNo) { infoDialog = 1 }
|
||||
Spacer(Modifier.padding(vertical = 8.dp))
|
||||
if(VERSION.SDK_INT >= 23) CardItem(R.string.system_user, userManager.isSystemUser.yesOrNo)
|
||||
if(VERSION.SDK_INT >= 34) CardItem(R.string.admin_user, userManager.isAdminUser.yesOrNo)
|
||||
if(VERSION.SDK_INT >= 25) CardItem(R.string.demo_user, userManager.isDemoUser.yesOrNo)
|
||||
if(VERSION.SDK_INT >= 26) CardItem(R.string.creation_time, parseTimestamp(userManager.getUserCreationTime(user)))
|
||||
if (VERSION.SDK_INT >= 28) {
|
||||
CardItem(R.string.logout_enabled, dpm.isLogoutEnabled.yesOrNo())
|
||||
CardItem(R.string.logout_enabled, dpm.isLogoutEnabled.yesOrNo)
|
||||
if(context.isDeviceOwner || context.isProfileOwner) {
|
||||
CardItem(R.string.ephemeral_user, dpm.isEphemeralUser(receiver).yesOrNo())
|
||||
CardItem(R.string.ephemeral_user, dpm.isEphemeralUser(receiver).yesOrNo)
|
||||
}
|
||||
CardItem(R.string.affiliated_user, dpm.isAffiliatedUser.yesOrNo())
|
||||
CardItem(R.string.affiliated_user, dpm.isAffiliatedUser.yesOrNo)
|
||||
}
|
||||
CardItem(R.string.user_id, (Binder.getCallingUid() / 100000).toString())
|
||||
CardItem(R.string.user_serial_number, userManager.getSerialNumberForUser(Process.myUserHandle()).toString())
|
||||
Spacer(Modifier.padding(vertical = 30.dp))
|
||||
}
|
||||
if(infoDialog != 0) AlertDialog(
|
||||
text = { Text(stringResource(R.string.info_headless_system_user_mode)) },
|
||||
confirmButton = {
|
||||
TextButton(onClick = { infoDialog = 0 }) {
|
||||
Text(stringResource(R.string.confirm))
|
||||
}
|
||||
},
|
||||
onDismissRequest = { infoDialog = 0 }
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -201,26 +262,35 @@ private fun UserOperation() {
|
||||
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
|
||||
val dpm = context.getDPM()
|
||||
val receiver = context.getReceiver()
|
||||
var idInput by remember { mutableStateOf("") }
|
||||
var useUid by remember { mutableStateOf(false) }
|
||||
val focusMgr = LocalFocusManager.current
|
||||
fun withUserHandle(operation: (UserHandle) -> Unit) {
|
||||
val userHandle = if(useUid && VERSION.SDK_INT >= 24) {
|
||||
UserHandle.getUserHandleForUid(idInput.toInt())
|
||||
} else {
|
||||
userManager.getUserForSerialNumber(idInput.toLong())
|
||||
}
|
||||
if(userHandle == null) {
|
||||
Toast.makeText(context, R.string.user_not_exist, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
operation(userHandle)
|
||||
}
|
||||
}
|
||||
val legalInput = try {
|
||||
idInput.toInt()
|
||||
true
|
||||
} catch(_: Exception) {
|
||||
false
|
||||
}
|
||||
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) {
|
||||
Spacer(Modifier.padding(vertical = 10.dp))
|
||||
Text(text = stringResource(R.string.user_operation), style = typography.headlineLarge)
|
||||
var idInput by remember { mutableStateOf("") }
|
||||
var userHandleById: UserHandle by remember { mutableStateOf(Process.myUserHandle()) }
|
||||
var useUid by remember { mutableStateOf(false) }
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
OutlinedTextField(
|
||||
value = idInput,
|
||||
onValueChange = {
|
||||
idInput = it
|
||||
if(useUid) {
|
||||
if(idInput != "" && VERSION.SDK_INT >= 24) {
|
||||
userHandleById = UserHandle.getUserHandleForUid(idInput.toInt())
|
||||
}
|
||||
}else{
|
||||
val userHandleBySerial = userManager.getUserForSerialNumber(idInput.toLong())
|
||||
userHandleById = userHandleBySerial ?: Process.myUserHandle()
|
||||
}
|
||||
},
|
||||
label = { Text(if(useUid) "UID" else stringResource(R.string.serial_number)) },
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
@@ -231,27 +301,16 @@ private fun UserOperation() {
|
||||
if(VERSION.SDK_INT >= 24) {
|
||||
CheckBoxItem(text = R.string.use_uid, checked = useUid, operation = { idInput=""; useUid = it })
|
||||
}
|
||||
Spacer(Modifier.padding(vertical = 5.dp))
|
||||
if(VERSION.SDK_INT > 28) {
|
||||
if(context.isProfileOwner && dpm.isAffiliatedUser) {
|
||||
Button(
|
||||
onClick = {
|
||||
val result = dpm.logoutUser(receiver)
|
||||
Toast.makeText(context, userOperationResultCode(result, context), Toast.LENGTH_SHORT).show()
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(stringResource(R.string.logout_current_user))
|
||||
}
|
||||
}
|
||||
}
|
||||
if(VERSION.SDK_INT >= 28) {
|
||||
Button(
|
||||
onClick = {
|
||||
focusMgr.clearFocus()
|
||||
val result = dpm.startUserInBackground(receiver, userHandleById)
|
||||
Toast.makeText(context, userOperationResultCode(result, context), Toast.LENGTH_SHORT).show()
|
||||
withUserHandle {
|
||||
val result = dpm.startUserInBackground(receiver, it)
|
||||
Toast.makeText(context, userOperationResultCode(result), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
},
|
||||
enabled = legalInput,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(stringResource(R.string.start_in_background))
|
||||
@@ -260,8 +319,11 @@ private fun UserOperation() {
|
||||
Button(
|
||||
onClick = {
|
||||
focusMgr.clearFocus()
|
||||
Toast.makeText(context, if(dpm.switchUser(receiver,userHandleById)) R.string.success else R.string.failed, Toast.LENGTH_SHORT).show()
|
||||
withUserHandle {
|
||||
Toast.makeText(context, if(dpm.switchUser(receiver, it)) R.string.success else R.string.failed, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
},
|
||||
enabled = legalInput,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(stringResource(R.string.user_operation_switch))
|
||||
@@ -270,13 +332,12 @@ private fun UserOperation() {
|
||||
Button(
|
||||
onClick = {
|
||||
focusMgr.clearFocus()
|
||||
try{
|
||||
val result = dpm.stopUser(receiver,userHandleById)
|
||||
Toast.makeText(context, userOperationResultCode(result,context), Toast.LENGTH_SHORT).show()
|
||||
}catch(_: IllegalArgumentException) {
|
||||
Toast.makeText(context, R.string.failed, Toast.LENGTH_SHORT).show()
|
||||
withUserHandle {
|
||||
val result = dpm.stopUser(receiver, it)
|
||||
Toast.makeText(context, userOperationResultCode(result), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
},
|
||||
enabled = legalInput,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(stringResource(R.string.stop))
|
||||
@@ -285,13 +346,16 @@ private fun UserOperation() {
|
||||
Button(
|
||||
onClick = {
|
||||
focusMgr.clearFocus()
|
||||
if(dpm.removeUser(receiver,userHandleById)) {
|
||||
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
|
||||
idInput = ""
|
||||
}else{
|
||||
Toast.makeText(context, R.string.failed, Toast.LENGTH_SHORT).show()
|
||||
withUserHandle {
|
||||
if(dpm.removeUser(receiver, it)) {
|
||||
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
|
||||
idInput = ""
|
||||
} else {
|
||||
Toast.makeText(context, R.string.failed, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
},
|
||||
enabled = legalInput,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Text(stringResource(R.string.delete))
|
||||
@@ -593,12 +657,12 @@ private fun UserIcon() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun userOperationResultCode(result:Int, context: Context): String {
|
||||
return when(result) {
|
||||
UserManager.USER_OPERATION_SUCCESS->context.getString(R.string.success)
|
||||
UserManager.USER_OPERATION_ERROR_UNKNOWN-> context.getString(R.string.unknown_result)
|
||||
UserManager.USER_OPERATION_ERROR_MANAGED_PROFILE-> context.getString(R.string.fail_managed_profile)
|
||||
UserManager.USER_OPERATION_ERROR_CURRENT_USER-> context.getString(R.string.fail_current_user)
|
||||
else->context.getString(R.string.unknown)
|
||||
@StringRes
|
||||
private fun userOperationResultCode(result:Int): Int =
|
||||
when(result) {
|
||||
UserManager.USER_OPERATION_SUCCESS -> R.string.success
|
||||
UserManager.USER_OPERATION_ERROR_UNKNOWN -> R.string.unknown_error
|
||||
UserManager.USER_OPERATION_ERROR_MANAGED_PROFILE-> R.string.fail_managed_profile
|
||||
UserManager.USER_OPERATION_ERROR_CURRENT_USER-> R.string.fail_current_user
|
||||
else -> R.string.unknown
|
||||
}
|
||||
}
|
||||
|
||||
9
app/src/main/res/drawable/list_fill0.xml
Normal file
9
app/src/main/res/drawable/list_fill0.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:pathData="M280,360v-80h560v80L280,360ZM280,520v-80h560v80L280,520ZM280,680v-80h560v80L280,680ZM160,360q-17,0 -28.5,-11.5T120,320q0,-17 11.5,-28.5T160,280q17,0 28.5,11.5T200,320q0,17 -11.5,28.5T160,360ZM160,520q-17,0 -28.5,-11.5T120,480q0,-17 11.5,-28.5T160,440q17,0 28.5,11.5T200,480q0,17 -11.5,28.5T160,520ZM160,680q-17,0 -28.5,-11.5T120,640q0,-17 11.5,-28.5T160,600q17,0 28.5,11.5T200,640q0,17 -11.5,28.5T160,680Z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/logout_fill0.xml
Normal file
9
app/src/main/res/drawable/logout_fill0.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:pathData="M200,840q-33,0 -56.5,-23.5T120,760v-560q0,-33 23.5,-56.5T200,120h280v80L200,200v560h280v80L200,840ZM640,680 L585,622 687,520L360,520v-80h327L585,338l55,-58 200,200 -200,200Z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
||||
@@ -61,6 +61,7 @@
|
||||
<string name="on">On</string> <!--TODO-->
|
||||
<string name="off">Off</string> <!--TODO-->
|
||||
<string name="alias">Alias</string> <!--TODO-->
|
||||
<string name="unknown_error">Unknown error</string> <!--TODO-->
|
||||
|
||||
|
||||
<!--Разрешения-->
|
||||
@@ -451,14 +452,18 @@
|
||||
<string name="support_multiuser">Поддержка нескольких пользователей</string>
|
||||
<string name="system_user">Системный пользователь</string>
|
||||
<string name="admin_user">Пользователь-администратор</string>
|
||||
<string name="headless_system_user">Фоновый системный пользователь</string>
|
||||
<string name="demo_user">Demo user</string> <!--TODO-->
|
||||
<string name="headless_system_user_mode">Headless system user mode</string> <!--TODO-->
|
||||
<string name="creation_time">Creation time</string> <!--TODO-->
|
||||
<string name="logout_enabled">Выход из системы разрешен</string>
|
||||
<string name="ephemeral_user">Временный пользователь</string>
|
||||
<string name="affiliated_user">Связанный пользователь</string>
|
||||
<string name="user_id">Идентификатор пользователя</string>
|
||||
<string name="user_serial_number">Серийный номер пользователя</string>
|
||||
<string name="user_operation">Операция с пользователем</string>
|
||||
<string name="user_not_exist">User does not exist</string> <!--TODO-->
|
||||
<string name="serial_number">Серийный номер</string>
|
||||
<string name="secondary_users">Secondary users</string> <!--TODO-->
|
||||
<string name="use_uid">Использовать UID</string>
|
||||
<string name="logout_current_user">Выйти из текущего пользователя</string>
|
||||
<string name="start_in_background">Запустить в фоновом режиме</string>
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
<string name="on">On</string> <!--TODO-->
|
||||
<string name="off">Off</string> <!--TODO-->
|
||||
<string name="alias">Alias</string> <!--TODO-->
|
||||
<string name="unknown_error">Unknown error</string> <!--TODO-->
|
||||
|
||||
<!--Permissions-->
|
||||
<string name="click_to_activate">Etkinleştirmek İçin Tıklayın</string>
|
||||
@@ -449,13 +450,17 @@
|
||||
<string name="support_multiuser">Çoklu kullanıcı desteği</string>
|
||||
<string name="system_user">Sistem kullanıcısı</string>
|
||||
<string name="admin_user">Yönetici kullanıcısı</string>
|
||||
<string name="headless_system_user">Başsız sistem kullanıcısı</string>
|
||||
<string name="demo_user">Demo user</string> <!--TODO-->
|
||||
<string name="headless_system_user_mode">Headless system user mode</string> <!--TODO-->
|
||||
<string name="creation_time">Creation time</string> <!--TODO-->
|
||||
<string name="logout_enabled">Logout enabled</string> <!--TODO-->
|
||||
<string name="ephemeral_user">Geçici kullanıcı</string>
|
||||
<string name="affiliated_user">Bağlı kullanıcı</string>
|
||||
<string name="user_id">Kullanıcı ID</string>
|
||||
<string name="user_serial_number">Kullanıcı seri numarası</string>
|
||||
<string name="secondary_users">Secondary users</string> <!--TODO-->
|
||||
<string name="user_operation">Kullanıcı işlemi</string>
|
||||
<string name="user_not_exist">User does not exist</string> <!--TODO-->
|
||||
<string name="serial_number">Seri numarası</string>
|
||||
<string name="use_uid">UID kullan</string>
|
||||
<string name="logout_current_user">Mevcut kullanıcıyı çıkış yap</string>
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
<string name="on">开启</string>
|
||||
<string name="off">关闭</string>
|
||||
<string name="alias">别名</string>
|
||||
<string name="unknown_error">未知错误</string>
|
||||
|
||||
<!--Permissions-->
|
||||
<string name="click_to_activate">点击以激活</string>
|
||||
@@ -441,13 +442,17 @@
|
||||
<string name="support_multiuser">支持多用户</string>
|
||||
<string name="system_user">系统用户</string>
|
||||
<string name="admin_user">管理员用户</string>
|
||||
<string name="headless_system_user">无头系统用户</string>
|
||||
<string name="demo_user">演示用户</string>
|
||||
<string name="headless_system_user_mode">无头系统用户模式</string>
|
||||
<string name="creation_time">创建时间</string>
|
||||
<string name="logout_enabled">用户可登出</string>
|
||||
<string name="ephemeral_user">临时用户</string>
|
||||
<string name="affiliated_user">附属用户</string>
|
||||
<string name="user_id">当前UserID</string>
|
||||
<string name="user_serial_number">当前用户序列号</string>
|
||||
<string name="secondary_users">次要用户</string>
|
||||
<string name="user_operation">用户操作</string>
|
||||
<string name="user_not_exist">用户不存在</string>
|
||||
<string name="serial_number">序列号</string>
|
||||
<string name="use_uid">使用UID</string>
|
||||
<string name="logout_current_user">登出当前用户</string>
|
||||
@@ -626,6 +631,7 @@
|
||||
<string name="info_suspend_app">挂起的应用无法被打开,通知会被隐藏,不会在最近任务中显示,不能弹窗,不能发送Toast。\n有些应用无法被挂起,比如Device admin、启动器和默认拨号应用。</string>
|
||||
<string name="info_disable_user_control">用户无法清除这些应用的存储空间,也无法强制停止应用</string>
|
||||
<string name="info_keep_uninstalled_apps">这个列表中的应用的APK将会一直保留,即使没有任何用户安装这个应用</string>
|
||||
<string name="info_headless_system_user_mode">无头系统用户模式意味着系统用户运行系统服务和一些系统UI,但它不与任何真实的人相关联,必须创建额外的用户才能与真实的人相关联。</string>
|
||||
<string name="info_user_operation">推荐使用用户序列号来标识用户,如果要使用UID,UID可以是运行在目标用户中任意应用的UID</string>
|
||||
<string name="info_affiliated_id">当Device owner创建并管理用户时,新的用户不是附属用户。Device owner设置和受管理用户完全相同的附属用户ID后,受管理用户成为附属于Device owner的用户</string>
|
||||
<string name="info_reset_password">设置一个新的密码,密码的长度需要4位或以上,不输入密码将会清除现有的密码。长度在6位或以下的纯数字密码将会设置为PIN码。</string>
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
<string name="on">On</string>
|
||||
<string name="off">Off</string>
|
||||
<string name="alias">Alias</string>
|
||||
<string name="unknown_error">Unknown error</string>
|
||||
|
||||
<!--Permissions-->
|
||||
<string name="click_to_activate">Click to activate</string>
|
||||
@@ -455,13 +456,17 @@
|
||||
<string name="support_multiuser">Support multiuser</string>
|
||||
<string name="system_user">System user</string>
|
||||
<string name="admin_user">Admin user</string>
|
||||
<string name="headless_system_user">Headless system user</string>
|
||||
<string name="demo_user">Demo user</string>
|
||||
<string name="headless_system_user_mode">Headless system user mode</string>
|
||||
<string name="creation_time">Creation time</string>
|
||||
<string name="logout_enabled">Logout enabled</string>
|
||||
<string name="ephemeral_user">Ephemeral user</string>
|
||||
<string name="affiliated_user">Affiliated user</string>
|
||||
<string name="user_id">UserID</string>
|
||||
<string name="user_serial_number">User serial number</string>
|
||||
<string name="secondary_users">Secondary users</string>
|
||||
<string name="user_operation">User operation</string>
|
||||
<string name="user_not_exist">User does not exist</string>
|
||||
<string name="serial_number">Serial number</string>
|
||||
<string name="use_uid">Use UID</string>
|
||||
<string name="logout_current_user">Logout current user</string>
|
||||
@@ -640,6 +645,7 @@
|
||||
<string name="info_suspend_app">A suspended package will not be able to start activities. Its notifications will be hidden, it will not show up in recent activities, will not be able to show toasts or dialogs or ring the device.\nSome apps cannot be suspended, such as device admins, the active launcher and the default dialer.</string>
|
||||
<string name="info_disable_user_control">User will not be able to clear app data or force-stop packages.</string>
|
||||
<string name="info_keep_uninstalled_apps">Set a list of apps to keep around as APKs even if no user has currently installed it. </string>
|
||||
<string name="info_headless_system_user_mode">Headless system user mode means the system user runs system services and some system UI, but it is not associated with any real person and additional users must be created to be associated with real persons.</string>
|
||||
<string name="info_user_operation">It is recommended to specify a user with serial number, you can also use UID, the UID should be any of the apps in the target user.</string>
|
||||
<string name="info_affiliated_id">When Device owner create a managed user, the managed user isn\'t affiliated. In order to make the managed user affiliated with the Device owner, you should set same affiliated IDs in main user and managed user</string>
|
||||
<string name="info_reset_password">Set a new lockscreen password. The length of this password must be at least 4 digits. Keep it empty to remove password.\nIf you set a numeric password that length is 6 or lower, it will set as PIN</string>
|
||||
|
||||
Reference in New Issue
Block a user