Set default Affiliation ID while app launch

Wipe data warning timer
Display profile owner entry in non-system users
Fix some UI bugs
This commit is contained in:
BinTianqi
2024-11-17 10:40:01 +08:00
parent 017ed57f64
commit 2c1898e4a0
12 changed files with 112 additions and 47 deletions

View File

@@ -48,6 +48,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
@@ -66,12 +67,14 @@ import com.bintianqi.owndroid.dpm.getReceiver
import com.bintianqi.owndroid.dpm.isDeviceAdmin import com.bintianqi.owndroid.dpm.isDeviceAdmin
import com.bintianqi.owndroid.dpm.isDeviceOwner import com.bintianqi.owndroid.dpm.isDeviceOwner
import com.bintianqi.owndroid.dpm.isProfileOwner import com.bintianqi.owndroid.dpm.isProfileOwner
import com.bintianqi.owndroid.dpm.setDefaultAffiliationID
import com.bintianqi.owndroid.dpm.toggleInstallAppActivity import com.bintianqi.owndroid.dpm.toggleInstallAppActivity
import com.bintianqi.owndroid.ui.Animations import com.bintianqi.owndroid.ui.Animations
import com.bintianqi.owndroid.ui.theme.OwnDroidTheme import com.bintianqi.owndroid.ui.theme.OwnDroidTheme
import com.rosan.dhizuku.api.Dhizuku import com.rosan.dhizuku.api.Dhizuku
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import org.lsposed.hiddenapibypass.HiddenApiBypass import org.lsposed.hiddenapibypass.HiddenApiBypass
import java.util.Locale import java.util.Locale
@@ -85,16 +88,18 @@ class MainActivity : FragmentActivity() {
enableEdgeToEdge() enableEdgeToEdge()
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val sharedPref = applicationContext.getSharedPreferences("data", MODE_PRIVATE) val context = applicationContext
val sharedPref = context.getSharedPreferences("data", MODE_PRIVATE)
if (VERSION.SDK_INT >= 28) HiddenApiBypass.setHiddenApiExemptions("") if (VERSION.SDK_INT >= 28) HiddenApiBypass.setHiddenApiExemptions("")
if(sharedPref.getBoolean("auth", false)) { if(sharedPref.getBoolean("auth", false)) {
showAuth.value = true showAuth.value = true
} }
val locale = applicationContext.resources?.configuration?.locale val locale = context.resources?.configuration?.locale
zhCN = locale == Locale.SIMPLIFIED_CHINESE || locale == Locale.CHINESE || locale == Locale.CHINA zhCN = locale == Locale.SIMPLIFIED_CHINESE || locale == Locale.CHINESE || locale == Locale.CHINA
toggleInstallAppActivity() toggleInstallAppActivity()
val vm by viewModels<MyViewModel>() val vm by viewModels<MyViewModel>()
if(!vm.initialized) vm.initialize(applicationContext) if(!vm.initialized) vm.initialize(context)
lifecycleScope.launch { setDefaultAffiliationID(context) }
setContent { setContent {
OwnDroidTheme(vm) { OwnDroidTheme(vm) {
Home(vm) Home(vm)

View File

@@ -1,5 +1,6 @@
package com.bintianqi.owndroid package com.bintianqi.owndroid
import android.os.Build
import android.os.Bundle import android.os.Bundle
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
@@ -11,6 +12,7 @@ import androidx.compose.ui.res.stringResource
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import com.bintianqi.owndroid.ui.theme.OwnDroidTheme import com.bintianqi.owndroid.ui.theme.OwnDroidTheme
import kotlin.system.exitProcess
class ManageSpaceActivity: FragmentActivity() { class ManageSpaceActivity: FragmentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@@ -32,21 +34,26 @@ class ManageSpaceActivity: FragmentActivity() {
}, },
onDismissRequest = { finish() }, onDismissRequest = { finish() },
dismissButton = { dismissButton = {
if(!protected) TextButton(onClick = { finish() }) { TextButton(onClick = { finish() }) {
Text(stringResource(R.string.cancel)) Text(stringResource(R.string.cancel))
} }
}, },
confirmButton = { confirmButton = {
TextButton( if(!protected) TextButton(
onClick = { onClick = {
if(!protected) { filesDir.deleteRecursively()
applicationContext.filesDir.deleteRecursively() cacheDir.deleteRecursively()
codeCacheDir.deleteRecursively()
if(Build.VERSION.SDK_INT >= 24) {
dataDir.resolve("shared_prefs").deleteRecursively()
} else {
sharedPref.edit().clear().apply() sharedPref.edit().clear().apply()
} }
finish() finish()
exitProcess(0)
} }
) { ) {
Text(stringResource(if(protected) R.string.cancel else R.string.confirm)) Text(stringResource(R.string.confirm))
} }
} }
) )

View File

@@ -470,9 +470,9 @@ private fun PermissionManage(pkgName: String) {
Text(selectedPermission.permission) Text(selectedPermission.permission)
Spacer(Modifier.padding(vertical = 4.dp)) Spacer(Modifier.padding(vertical = 4.dp))
if(!(VERSION.SDK_INT >=31 && context.isProfileOwner && selectedPermission.profileOwnerRestricted)) { if(!(VERSION.SDK_INT >=31 && context.isProfileOwner && selectedPermission.profileOwnerRestricted)) {
GrantPermissionItem(R.string.grant, PERMISSION_GRANT_STATE_GRANTED) GrantPermissionItem(R.string.granted, PERMISSION_GRANT_STATE_GRANTED)
} }
GrantPermissionItem(R.string.deny, PERMISSION_GRANT_STATE_DENIED) GrantPermissionItem(R.string.denied, PERMISSION_GRANT_STATE_DENIED)
GrantPermissionItem(R.string.default_stringres, PERMISSION_GRANT_STATE_DEFAULT) GrantPermissionItem(R.string.default_stringres, PERMISSION_GRANT_STATE_DEFAULT)
} }
} }

View File

@@ -16,6 +16,7 @@ import android.content.pm.IPackageInstaller
import android.content.pm.PackageInstaller import android.content.pm.PackageInstaller
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Build.VERSION import android.os.Build.VERSION
import android.os.UserManager
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
@@ -401,3 +402,24 @@ data class SecurityEventItem(
@SerialName("log_level") val logLevel: Int?, @SerialName("log_level") val logLevel: Int?,
val data: String val data: String
) )
fun setDefaultAffiliationID(context: Context) {
if(VERSION.SDK_INT < 26) return
val sharedPrefs = context.getSharedPreferences("data", Context.MODE_PRIVATE)
if(!sharedPrefs.getBoolean("default_affiliation_id_set", false)) {
try {
val um = context.getSystemService(Context.USER_SERVICE) as UserManager
if(context.isDeviceOwner || (!um.isSystemUser && context.isProfileOwner)) {
val dpm = context.getDPM()
val receiver = context.getReceiver()
val affiliationIDs = dpm.getAffiliationIds(receiver)
if(affiliationIDs.isEmpty()) {
dpm.setAffiliationIds(receiver, setOf("OwnDroid_default_affiliation_id"))
sharedPrefs.edit().putBoolean("default_affiliation_id_set", true).apply()
}
}
} catch(e: Exception) {
e.printStackTrace()
}
}
}

View File

@@ -700,7 +700,7 @@ private fun WifiAuthKeypair() {
Spacer(Modifier.padding(vertical = 5.dp)) Spacer(Modifier.padding(vertical = 5.dp))
OutlinedTextField( OutlinedTextField(
value = keyPair, value = keyPair,
label = { Text(stringResource(R.string.keypair)) }, label = { Text(stringResource(R.string.alias)) },
onValueChange = { keyPair = it }, onValueChange = { keyPair = it },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }), keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
@@ -723,7 +723,7 @@ private fun WifiAuthKeypair() {
}, },
modifier = Modifier.fillMaxWidth(0.49F) modifier = Modifier.fillMaxWidth(0.49F)
) { ) {
Text(stringResource(R.string.add)) Text(stringResource(R.string.grant))
} }
Button( Button(
onClick = { onClick = {
@@ -732,7 +732,7 @@ private fun WifiAuthKeypair() {
}, },
modifier = Modifier.fillMaxWidth(0.96F) modifier = Modifier.fillMaxWidth(0.96F)
) { ) {
Text(stringResource(R.string.remove)) Text(stringResource(R.string.revoke))
} }
} }
} }

View File

@@ -7,8 +7,10 @@ import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Binder
import android.os.Build.VERSION import android.os.Build.VERSION
import android.os.RemoteException import android.os.RemoteException
import android.os.UserManager
import android.widget.Toast import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.* import androidx.compose.foundation.*
@@ -90,6 +92,7 @@ private fun Home(localNavCtrl:NavHostController,listScrollState:ScrollState) {
val deviceAdmin = context.isDeviceAdmin val deviceAdmin = context.isDeviceAdmin
val deviceOwner = context.isDeviceOwner val deviceOwner = context.isDeviceOwner
val profileOwner = context.isProfileOwner val profileOwner = context.isProfileOwner
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
var dialog by remember { mutableIntStateOf(0) } var dialog by remember { mutableIntStateOf(0) }
val enrollmentSpecificId = if(VERSION.SDK_INT >= 31 && (deviceOwner || profileOwner)) dpm.enrollmentSpecificId else "" val enrollmentSpecificId = if(VERSION.SDK_INT >= 31 && (deviceOwner || profileOwner)) dpm.enrollmentSpecificId else ""
Column(modifier = Modifier.fillMaxSize().verticalScroll(listScrollState)) { Column(modifier = Modifier.fillMaxSize().verticalScroll(listScrollState)) {
@@ -110,13 +113,13 @@ private fun Home(localNavCtrl:NavHostController,listScrollState:ScrollState) {
R.string.device_admin, stringResource(if(deviceAdmin) R.string.activated else R.string.deactivated), R.string.device_admin, stringResource(if(deviceAdmin) R.string.activated else R.string.deactivated),
operation = { localNavCtrl.navigate("DeviceAdmin") } operation = { localNavCtrl.navigate("DeviceAdmin") }
) )
if(profileOwner) { if(profileOwner || !userManager.isSystemUser) {
SubPageItem( SubPageItem(
R.string.profile_owner, stringResource(R.string.activated), R.string.profile_owner, stringResource(if(profileOwner) R.string.activated else R.string.deactivated),
operation = { localNavCtrl.navigate("ProfileOwner") } operation = { localNavCtrl.navigate("ProfileOwner") }
) )
} }
if(!profileOwner) { if(!profileOwner && userManager.isSystemUser) {
SubPageItem( SubPageItem(
R.string.device_owner, stringResource(if(deviceOwner) R.string.activated else R.string.deactivated), R.string.device_owner, stringResource(if(deviceOwner) R.string.activated else R.string.deactivated),
operation = { localNavCtrl.navigate("DeviceOwner") } operation = { localNavCtrl.navigate("DeviceOwner") }
@@ -376,7 +379,13 @@ private fun ProfileOwner() {
Text(stringResource(R.string.deactivate)) Text(stringResource(R.string.deactivate))
} }
} }
InfoCard(R.string.profile_owner) if(!profileOwner) {
val command = context.getString(R.string.activate_profile_owner_command, (Binder.getCallingUid() / 100000).toString())
SelectionContainer {
Text(command)
}
CopyTextButton(R.string.copy_command, command)
}
} }
if(deactivateDialog && VERSION.SDK_INT >= 24) { if(deactivateDialog && VERSION.SDK_INT >= 24) {
AlertDialog( AlertDialog(
@@ -394,7 +403,8 @@ private fun ProfileOwner() {
onClick = { onClick = {
dpm.clearProfileOwner(receiver) dpm.clearProfileOwner(receiver)
deactivateDialog = false deactivateDialog = false
} },
colors = ButtonDefaults.textButtonColors(contentColor = colorScheme.error)
) { ) {
Text(stringResource(R.string.confirm)) Text(stringResource(R.string.confirm))
} }

View File

@@ -13,6 +13,7 @@ import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.foundation.text.selection.SelectionContainer
@@ -192,9 +193,7 @@ fun ShizukuActivate() {
} }
} }
SelectionContainer(modifier = Modifier SelectionContainer(modifier = Modifier.fillMaxWidth().horizontalScroll(outputTextScrollState)) {
.align(Alignment.Start)
.horizontalScroll(outputTextScrollState)) {
Text(text = outputText, softWrap = false, modifier = Modifier.padding(4.dp)) Text(text = outputText, softWrap = false, modifier = Modifier.padding(4.dp))
} }

View File

@@ -125,6 +125,7 @@ import com.bintianqi.owndroid.ui.SubPageItem
import com.bintianqi.owndroid.ui.SwitchItem import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.ui.TopBar import com.bintianqi.owndroid.ui.TopBar
import com.bintianqi.owndroid.uriToStream import com.bintianqi.owndroid.uriToStream
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
@@ -1255,7 +1256,6 @@ private fun WipeData() {
val context = LocalContext.current val context = LocalContext.current
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var warning by remember { mutableStateOf(false) } var warning by remember { mutableStateOf(false) }
var wipeDevice by remember { mutableStateOf(false) } var wipeDevice by remember { mutableStateOf(false) }
@@ -1333,6 +1333,14 @@ private fun WipeData() {
}, },
onDismissRequest = { warning = false }, onDismissRequest = { warning = false },
confirmButton = { confirmButton = {
var timer by remember { mutableIntStateOf(6) }
LaunchedEffect(Unit) {
while(timer > 0) {
timer -= 1
delay(1000)
}
}
val timerText = if(timer > 0) "(${timer}s)" else ""
TextButton( TextButton(
onClick = { onClick = {
var flag = 0 var flag = 0
@@ -1350,9 +1358,11 @@ private fun WipeData() {
} }
} }
}, },
colors = ButtonDefaults.textButtonColors(contentColor = colorScheme.error) colors = ButtonDefaults.textButtonColors(contentColor = colorScheme.error),
modifier = Modifier.animateContentSize(),
enabled = timer == 0
) { ) {
Text(stringResource(R.string.confirm)) Text(stringResource(R.string.confirm) + timerText)
} }
}, },
dismissButton = { dismissButton = {
@@ -1392,27 +1402,30 @@ private fun SysUpdatePolicy() {
RadioButtonItem(R.string.none, selectedPolicy == null, { selectedPolicy = null }) RadioButtonItem(R.string.none, selectedPolicy == null, { selectedPolicy = null })
var windowedPolicyStart by remember { mutableStateOf("") } var windowedPolicyStart by remember { mutableStateOf("") }
var windowedPolicyEnd by remember { mutableStateOf("") } var windowedPolicyEnd by remember { mutableStateOf("") }
if(selectedPolicy == 2) { AnimatedVisibility(selectedPolicy == 2) {
Spacer(Modifier.padding(vertical = 3.dp)) Column {
OutlinedTextField( Row(
value = windowedPolicyStart, horizontalArrangement = Arrangement.SpaceBetween
label = { Text(stringResource(R.string.start_time)) }, ) {
onValueChange = { windowedPolicyStart = it }, OutlinedTextField(
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done), value = windowedPolicyStart,
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }), label = { Text(stringResource(R.string.start_time)) },
modifier = Modifier.fillMaxWidth(0.5F) onValueChange = { windowedPolicyStart = it },
) keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
Spacer(Modifier.padding(horizontal = 3.dp)) keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
OutlinedTextField( modifier = Modifier.fillMaxWidth(0.49F)
value = windowedPolicyEnd, )
onValueChange = {windowedPolicyEnd = it }, OutlinedTextField(
label = { Text(stringResource(R.string.end_time)) }, value = windowedPolicyEnd,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done), onValueChange = {windowedPolicyEnd = it },
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }), label = { Text(stringResource(R.string.end_time)) },
modifier = Modifier.fillMaxWidth() keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
) keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
Spacer(Modifier.padding(vertical = 3.dp)) modifier = Modifier.fillMaxWidth(0.96F).padding(bottom = 2.dp)
Text(text = stringResource(R.string.minutes_in_one_day)) )
}
Text(text = stringResource(R.string.minutes_in_one_day))
}
} }
Button( Button(
onClick = { onClick = {
@@ -1426,7 +1439,7 @@ private fun SysUpdatePolicy() {
dpm.setSystemUpdatePolicy(receiver,policy) dpm.setSystemUpdatePolicy(receiver,policy)
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show() Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
}, },
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth().padding(top = 8.dp)
) { ) {
Text(stringResource(R.string.apply)) Text(stringResource(R.string.apply))
} }

View File

@@ -22,6 +22,7 @@
<string name="denied">Запрещено</string> <string name="denied">Запрещено</string>
<string name="grant">Разрешить</string> <string name="grant">Разрешить</string>
<string name="deny">Запретить</string> <string name="deny">Запретить</string>
<string name="revoke">Revoke</string> <!--TODO-->
<string name="current_state">Текущее состояние: %1$s</string> <string name="current_state">Текущее состояние: %1$s</string>
<string name="auto">Авто</string> <string name="auto">Авто</string>
<string name="password">Пароль</string> <string name="password">Пароль</string>
@@ -59,6 +60,7 @@
<string name="next">Следующий</string> <string name="next">Следующий</string>
<string name="on">On</string> <!--TODO--> <string name="on">On</string> <!--TODO-->
<string name="off">Off</string> <!--TODO--> <string name="off">Off</string> <!--TODO-->
<string name="alias">Alias</string> <!--TODO-->
<!--Разрешения--> <!--Разрешения-->

View File

@@ -23,6 +23,7 @@
<string name="denied">Reddedildi</string> <string name="denied">Reddedildi</string>
<string name="grant">Ver</string> <string name="grant">Ver</string>
<string name="deny">Reddet</string> <string name="deny">Reddet</string>
<string name="revoke">Revoke</string> <!--TODO-->
<string name="current_state">Mevcut Durum: %1$s</string> <string name="current_state">Mevcut Durum: %1$s</string>
<string name="auto">Otomatik</string> <string name="auto">Otomatik</string>
<string name="password">Şifre</string> <string name="password">Şifre</string>
@@ -60,6 +61,7 @@
<string name="next">Next</string> <!--TODO--> <string name="next">Next</string> <!--TODO-->
<string name="on">On</string> <!--TODO--> <string name="on">On</string> <!--TODO-->
<string name="off">Off</string> <!--TODO--> <string name="off">Off</string> <!--TODO-->
<string name="alias">Alias</string> <!--TODO-->
<!--Permissions--> <!--Permissions-->
<string name="click_to_activate">Etkinleştirmek İçin Tıklayın</string> <string name="click_to_activate">Etkinleştirmek İçin Tıklayın</string>

View File

@@ -20,8 +20,9 @@
<string name="whitelist">白名单</string> <string name="whitelist">白名单</string>
<string name="granted">允许</string> <string name="granted">允许</string>
<string name="denied">拒绝</string> <string name="denied">拒绝</string>
<string name="grant">允许</string> <string name="grant">授予</string>
<string name="deny">拒绝</string> <string name="deny">拒绝</string>
<string name="revoke">吊销</string>
<string name="current_state">当前状态:%1$s</string> <string name="current_state">当前状态:%1$s</string>
<string name="auto">自动</string> <string name="auto">自动</string>
<string name="password">密码</string> <string name="password">密码</string>
@@ -57,6 +58,7 @@
<string name="next">下一个</string> <string name="next">下一个</string>
<string name="on">开启</string> <string name="on">开启</string>
<string name="off">关闭</string> <string name="off">关闭</string>
<string name="alias">别名</string>
<!--Permissions--> <!--Permissions-->
<string name="click_to_activate">点击以激活</string> <string name="click_to_activate">点击以激活</string>

View File

@@ -23,6 +23,7 @@
<string name="denied">Denied</string> <string name="denied">Denied</string>
<string name="grant">Grant</string> <string name="grant">Grant</string>
<string name="deny">Deny</string> <string name="deny">Deny</string>
<string name="revoke">Revoke</string>
<string name="current_state">Current status: %1$s</string> <string name="current_state">Current status: %1$s</string>
<string name="auto">Auto</string> <string name="auto">Auto</string>
<string name="password">Password</string> <string name="password">Password</string>
@@ -60,6 +61,7 @@
<string name="next">Next</string> <string name="next">Next</string>
<string name="on">On</string> <string name="on">On</string>
<string name="off">Off</string> <string name="off">Off</string>
<string name="alias">Alias</string>
<!--Permissions--> <!--Permissions-->
<string name="click_to_activate">Click to activate</string> <string name="click_to_activate">Click to activate</string>
@@ -71,6 +73,7 @@
<string name="reset_device_policy">Reset device policy</string> <string name="reset_device_policy">Reset device policy</string>
<string name="activate_device_admin">Activate Device admin</string> <string name="activate_device_admin">Activate Device admin</string>
<string name="activate_device_admin_command" translatable="false">dpm set-active-admin com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver</string> <string name="activate_device_admin_command" translatable="false">dpm set-active-admin com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver</string>
<string name="activate_profile_owner_command" translatable="false">dpm set-profile-owner --user %1$s com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver</string>
<string name="activate_device_owner_command" translatable="false">dpm set-device-owner com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver</string> <string name="activate_device_owner_command" translatable="false">dpm set-device-owner com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver</string>
<string name="device_info">Device info</string> <string name="device_info">Device info</string>
<string name="support_device_id_attestation">Support Device ID attestation</string> <string name="support_device_id_attestation">Support Device ID attestation</string>