Bind Shizuku service before navigate to it

Fix CI building
This commit is contained in:
BinTianqi
2025-01-22 22:19:06 +08:00
parent a21db0da70
commit 0b90d7c0f3
12 changed files with 110 additions and 64 deletions

View File

@@ -61,7 +61,7 @@ jobs:
upload-telegram: upload-telegram:
name: Upload Builds name: Upload Builds
if: ${{ github.ref_name == 'dev' }} if: github.ref_name == 'dev'
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: ["build"] needs: ["build"]
steps: steps:
@@ -91,6 +91,6 @@ jobs:
mv ./$RELEASE_SIGNED_PWD/app-release.apk ./$RELEASE_SIGNED_PWD.apk && rm -rf ./$RELEASE_SIGNED_PWD mv ./$RELEASE_SIGNED_PWD/app-release.apk ./$RELEASE_SIGNED_PWD.apk && rm -rf ./$RELEASE_SIGNED_PWD
../binaries/telegram-bot-api --api-id=${{ secrets.TELEGRAM_API_APP_ID }} --api-hash=${{ secrets.TELEGRAM_API_HASH }} --local 2>&1 > /dev/null & ../binaries/telegram-bot-api --api-id=${{ secrets.TELEGRAM_API_APP_ID }} --api-hash=${{ secrets.TELEGRAM_API_HASH }} --local 2>&1 > /dev/null &
export token=${{ secrets.TELEGRAM_BOT_KEY }} export token=${{ secrets.TELEGRAM_BOT_KEY }}
curl -v "http://127.0.0.1:8081/bot$token/sendMediaGroup?chat_id=-1002216379163&media=%5B%7B%22type%22%3A%22document%22%2C%22media%22%3A%22attach%3A%2F%2FreleaseTest%22%7D%2C%7B%22type%22%3A%22document%22%2C%22media%22%3A%22attach%3A%2F%2FreleaseSigned%22%2C%22parse_mode%22%3A%22HTML%22%2C%22caption%22%3A${ESCAPED}%7D%5D" \ curl -v "http://127.0.0.1:8081/bot$token/sendMediaGroup?chat_id=-1002203528169&media=%5B%7B%22type%22%3A%22document%22%2C%22media%22%3A%22attach%3A%2F%2FreleaseTest%22%7D%2C%7B%22type%22%3A%22document%22%2C%22media%22%3A%22attach%3A%2F%2FreleaseSigned%22%2C%22parse_mode%22%3A%22HTML%22%2C%22caption%22%3A${ESCAPED}%7D%5D" \
-F releaseTest="@$RELEASE_TEST_PWD.apk" \ -F releaseTest="@$RELEASE_TEST_PWD.apk" \
-F releaseSigned="@$RELEASE_SIGNED_PWD.apk" -F releaseSigned="@$RELEASE_SIGNED_PWD.apk"

View File

@@ -1,6 +1,9 @@
package com.bintianqi.owndroid; package com.bintianqi.owndroid;
import android.accounts.Account;
interface IUserService { interface IUserService {
String execute(String command) = 1; String execute(String command) = 1;
int getUid() = 2; int getUid() = 2;
Account[] listAccounts() = 3;
} }

View File

@@ -59,6 +59,7 @@ import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.bintianqi.owndroid.dpm.AccountsViewer
import com.bintianqi.owndroid.dpm.AffiliationID import com.bintianqi.owndroid.dpm.AffiliationID
import com.bintianqi.owndroid.dpm.AlwaysOnVPNPackage import com.bintianqi.owndroid.dpm.AlwaysOnVPNPackage
import com.bintianqi.owndroid.dpm.ApplicationManage import com.bintianqi.owndroid.dpm.ApplicationManage
@@ -213,7 +214,8 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) {
composable(route = "HomePage") { HomePage(navCtrl) } composable(route = "HomePage") { HomePage(navCtrl) }
composable(route = "Permissions") { Permissions(navCtrl) } composable(route = "Permissions") { Permissions(navCtrl) }
composable(route = "Shizuku") { Shizuku(vm, navCtrl) } composable(route = "Shizuku") { Shizuku(navCtrl, it.arguments!!) }
composable(route = "AccountsViewer") { AccountsViewer(navCtrl, it.arguments!!) }
composable(route = "DeviceAdmin") { DeviceAdmin(navCtrl) } composable(route = "DeviceAdmin") { DeviceAdmin(navCtrl) }
composable(route = "ProfileOwner") { ProfileOwner(navCtrl) } composable(route = "ProfileOwner") { ProfileOwner(navCtrl) }
composable(route = "DeviceOwner") { DeviceOwner(navCtrl) } composable(route = "DeviceOwner") { DeviceOwner(navCtrl) }
@@ -360,7 +362,7 @@ private fun HomePage(navCtrl:NavHostController) {
val profileOwner = context.isProfileOwner val profileOwner = context.isProfileOwner
val refreshStatus by dhizukuErrorStatus.collectAsState() val refreshStatus by dhizukuErrorStatus.collectAsState()
LaunchedEffect(refreshStatus) { LaunchedEffect(refreshStatus) {
activated = context.isDeviceAdmin activated = context.isProfileOwner || context.isDeviceOwner
activateType = if(sharedPref.getBoolean("dhizuku", false)) context.getString(R.string.dhizuku) + " - " else "" activateType = if(sharedPref.getBoolean("dhizuku", false)) context.getString(R.string.dhizuku) + " - " else ""
activateType += context.getString( activateType += context.getString(
if(deviceOwner) { R.string.device_owner } if(deviceOwner) { R.string.device_owner }

View File

@@ -2,7 +2,6 @@ package com.bintianqi.owndroid
import android.content.Context import android.content.Context
import android.os.Build import android.os.Build
import android.os.IBinder
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@@ -12,7 +11,6 @@ class MyViewModel: ViewModel() {
val theme = MutableStateFlow(ThemeSettings()) val theme = MutableStateFlow(ThemeSettings())
val installedPackages = mutableListOf<PackageInfo>() val installedPackages = mutableListOf<PackageInfo>()
val selectedPackage = MutableStateFlow("") val selectedPackage = MutableStateFlow("")
val shizukuBinder = MutableStateFlow<IBinder?>(null)
var initialized = false var initialized = false
fun initialize(context: Context) { fun initialize(context: Context) {

View File

@@ -1,5 +1,6 @@
package com.bintianqi.owndroid package com.bintianqi.owndroid
import android.annotation.SuppressLint
import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManager
import android.content.ClipData import android.content.ClipData
import android.content.ClipboardManager import android.content.ClipboardManager
@@ -85,3 +86,8 @@ val Long.humanReadableDate: String
fun Context.showOperationResultToast(success: Boolean) { fun Context.showOperationResultToast(success: Boolean) {
Toast.makeText(this, if(success) R.string.success else R.string.failed, Toast.LENGTH_SHORT).show() Toast.makeText(this, if(success) R.string.success else R.string.failed, Toast.LENGTH_SHORT).show()
} }
@SuppressLint("PrivateApi")
fun getContext(): Context {
return Class.forName("android.app.ActivityThread").getMethod("currentApplication").invoke(null) as Context
}

View File

@@ -9,6 +9,7 @@ import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Binder import android.os.Binder
import android.os.Build.VERSION import android.os.Build.VERSION
import android.os.Bundle
import android.os.RemoteException import android.os.RemoteException
import android.os.UserManager import android.os.UserManager
import android.widget.Toast import android.widget.Toast
@@ -29,6 +30,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.backToHomeStateFlow import com.bintianqi.owndroid.backToHomeStateFlow
@@ -54,6 +56,7 @@ fun Permissions(navCtrl: NavHostController) {
val profileOwner = context.isProfileOwner val profileOwner = context.isProfileOwner
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
var dialog by remember { mutableIntStateOf(0) } var dialog by remember { mutableIntStateOf(0) }
var bindingShizuku by remember { mutableStateOf(false) }
val enrollmentSpecificId = if(VERSION.SDK_INT >= 31 && (deviceOwner || profileOwner)) dpm.enrollmentSpecificId else "" val enrollmentSpecificId = if(VERSION.SDK_INT >= 31 && (deviceOwner || profileOwner)) dpm.enrollmentSpecificId else ""
MyScaffold(R.string.permissions, 0.dp, navCtrl) { MyScaffold(R.string.permissions, 0.dp, navCtrl) {
if(!dpm.isDeviceOwnerApp(context.packageName)) { if(!dpm.isDeviceOwnerApp(context.packageName)) {
@@ -82,8 +85,19 @@ fun Permissions(navCtrl: NavHostController) {
} }
FunctionItem(R.string.shizuku) { FunctionItem(R.string.shizuku) {
try { try {
if(Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED) { navCtrl.navigate("Shizuku") } if(Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED) {
else if(Shizuku.shouldShowRequestPermissionRationale()) { bindingShizuku = true
val destination = navCtrl.graph.findNode("Shizuku")!!.id
bindShizukuService(context, { binder ->
val args = Bundle()
args.putBinder("binder", binder)
bindingShizuku = false
navCtrl.navigate(destination, args)
}, {
Toast.makeText(context, R.string.shizuku_service_disconnected, Toast.LENGTH_SHORT).show()
bindingShizuku = false
})
} else if(Shizuku.shouldShowRequestPermissionRationale()) {
Toast.makeText(context, R.string.permission_denied, Toast.LENGTH_SHORT).show() Toast.makeText(context, R.string.permission_denied, Toast.LENGTH_SHORT).show()
} else { } else {
Sui.init(context.packageName) Sui.init(context.packageName)
@@ -124,6 +138,11 @@ fun Permissions(navCtrl: NavHostController) {
FunctionItem(R.string.transfer_ownership, icon = R.drawable.admin_panel_settings_fill0) { navCtrl.navigate("TransferOwnership") } FunctionItem(R.string.transfer_ownership, icon = R.drawable.admin_panel_settings_fill0) { navCtrl.navigate("TransferOwnership") }
} }
} }
if(bindingShizuku) {
Dialog(onDismissRequest = { bindingShizuku = false }) {
CircularProgressIndicator()
}
}
if(dialog != 0) { if(dialog != 0) {
var input by remember { mutableStateOf("") } var input by remember { mutableStateOf("") }
AlertDialog( AlertDialog(

View File

@@ -1,22 +1,27 @@
package com.bintianqi.owndroid.dpm package com.bintianqi.owndroid.dpm
import android.accounts.Account
import android.content.ComponentName import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.ServiceConnection import android.content.ServiceConnection
import android.os.Binder import android.os.Binder
import android.os.Build.VERSION import android.os.Build.VERSION
import android.os.Bundle
import android.os.IBinder import android.os.IBinder
import android.widget.Toast import android.util.Log
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.background
import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth 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.shape.RoundedCornerShape
import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@@ -28,56 +33,39 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import com.bintianqi.owndroid.IUserService import com.bintianqi.owndroid.IUserService
import com.bintianqi.owndroid.MyViewModel
import com.bintianqi.owndroid.R import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.ui.MyScaffold import com.bintianqi.owndroid.ui.MyScaffold
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import rikka.shizuku.Shizuku import rikka.shizuku.Shizuku
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun Shizuku(vm: MyViewModel, navCtrl: NavHostController) { fun Shizuku(navCtrl: NavHostController, navArgs: Bundle) {
val context = LocalContext.current val context = LocalContext.current
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
val coScope = rememberCoroutineScope() val coScope = rememberCoroutineScope()
val outputTextScrollState = rememberScrollState() val outputTextScrollState = rememberScrollState()
var outputText by rememberSaveable { mutableStateOf("") } var outputText by rememberSaveable { mutableStateOf("") }
var showDeviceAdminButton by remember { mutableStateOf(!context.isDeviceAdmin) }
var showDeviceOwnerButton by remember { mutableStateOf(!context.isDeviceOwner) } var showDeviceOwnerButton by remember { mutableStateOf(!context.isDeviceOwner) }
var showOrgProfileOwnerButton by remember { mutableStateOf(true) } var showOrgProfileOwnerButton by remember { mutableStateOf(true) }
val binder by vm.shizukuBinder.collectAsStateWithLifecycle() val binder = navArgs.getBinder("binder")!!
var service by remember { mutableStateOf<IUserService?>(null) } var service by remember { mutableStateOf<IUserService?>(null) }
var loading by remember { mutableStateOf(true) }
LaunchedEffect(binder) {
if(binder != null && binder!!.pingBinder()) {
service = IUserService.Stub.asInterface(binder)
loading = false
} else {
service = null
}
}
LaunchedEffect(service) {
if(service == null && !loading) navCtrl.navigateUp()
}
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
if(binder == null) bindShizukuService(context, vm.shizukuBinder) service = if(binder.pingBinder()) {
IUserService.Stub.asInterface(binder)
} else {
null
}
} }
MyScaffold(R.string.shizuku, 0.dp, navCtrl, false) { MyScaffold(R.string.shizuku, 0.dp, navCtrl, false) {
if(loading) {
Dialog(onDismissRequest = { navCtrl.navigateUp() }) {
CircularProgressIndicator()
}
}
Button( Button(
onClick = { onClick = {
@@ -103,9 +91,16 @@ fun Shizuku(vm: MyViewModel, navCtrl: NavHostController) {
} }
Button( Button(
onClick = { onClick = {
coScope.launch{ Log.d("Shizuku", "List accounts")
try {
val accounts = service!!.listAccounts()
val dest = navCtrl.graph.findNode("AccountsViewer")!!.id
navCtrl.navigate(dest, Bundle().apply { putParcelableArray("accounts", accounts) })
} catch(_: Exception) {
outputText = service!!.execute("dumpsys account") outputText = service!!.execute("dumpsys account")
outputTextScrollState.animateScrollTo(0) coScope.launch{
outputTextScrollState.animateScrollTo(0)
}
} }
}, },
modifier = Modifier.align(Alignment.CenterHorizontally) modifier = Modifier.align(Alignment.CenterHorizontally)
@@ -114,23 +109,7 @@ fun Shizuku(vm: MyViewModel, navCtrl: NavHostController) {
} }
Spacer(Modifier.padding(vertical = 5.dp)) Spacer(Modifier.padding(vertical = 5.dp))
AnimatedVisibility(showDeviceAdminButton && showDeviceOwnerButton) { AnimatedVisibility(showDeviceOwnerButton, modifier = Modifier.align(Alignment.CenterHorizontally)) {
Button(
onClick = {
coScope.launch{
outputText = service!!.execute(context.getString(R.string.dpm_activate_da_command))
outputTextScrollState.animateScrollTo(0)
delay(500)
showDeviceAdminButton = !context.isDeviceAdmin
}
},
modifier = Modifier.align(Alignment.CenterHorizontally)
) {
Text(text = stringResource(R.string.activate_device_admin))
}
}
AnimatedVisibility(showDeviceOwnerButton) {
Button( Button(
onClick = { onClick = {
coScope.launch{ coScope.launch{
@@ -139,8 +118,7 @@ fun Shizuku(vm: MyViewModel, navCtrl: NavHostController) {
delay(500) delay(500)
showDeviceOwnerButton = !context.isDeviceOwner showDeviceOwnerButton = !context.isDeviceOwner
} }
}, }
modifier = Modifier.align(Alignment.CenterHorizontally)
) { ) {
Text(text = stringResource(R.string.activate_device_owner)) Text(text = stringResource(R.string.activate_device_owner))
} }
@@ -173,14 +151,17 @@ fun Shizuku(vm: MyViewModel, navCtrl: NavHostController) {
} }
} }
fun bindShizukuService(context: Context, shizukuBinder: MutableStateFlow<IBinder?>) { fun bindShizukuService(
context: Context,
onServiceConnected: (IBinder) -> Unit,
onServiceDisconnected: () -> Unit
) {
val userServiceConnection = object : ServiceConnection { val userServiceConnection = object : ServiceConnection {
override fun onServiceConnected(componentName: ComponentName, binder: IBinder) { override fun onServiceConnected(componentName: ComponentName, binder: IBinder) {
shizukuBinder.value = binder onServiceConnected(binder)
} }
override fun onServiceDisconnected(componentName: ComponentName) { override fun onServiceDisconnected(componentName: ComponentName) {
shizukuBinder.value = null onServiceDisconnected()
Toast.makeText(context, R.string.shizuku_service_disconnected, Toast.LENGTH_SHORT).show()
} }
} }
val userServiceArgs = Shizuku.UserServiceArgs(ComponentName(context, ShizukuService::class.java)) val userServiceArgs = Shizuku.UserServiceArgs(ComponentName(context, ShizukuService::class.java))
@@ -194,3 +175,24 @@ fun bindShizukuService(context: Context, shizukuBinder: MutableStateFlow<IBinder
e.printStackTrace() e.printStackTrace()
} }
} }
@Composable
fun AccountsViewer(navCtrl: NavHostController, navArgs: Bundle) {
val accounts = navArgs.getParcelableArray("accounts") as Array<Account>
MyScaffold(R.string.accounts, 8.dp, navCtrl, false) {
accounts.forEach {
Column(
modifier = Modifier
.fillMaxWidth().padding(vertical = 4.dp)
.clip(RoundedCornerShape(15)).background(MaterialTheme.colorScheme.surfaceVariant)
) {
SelectionContainer {
Column(modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp)) {
Text(stringResource(R.string.type) + ": " + it.type)
Text(stringResource(R.string.name) + ": " + it.name)
}
}
}
}
}
}

View File

@@ -1,10 +1,18 @@
package com.bintianqi.owndroid.dpm package com.bintianqi.owndroid.dpm
import android.accounts.Account
import android.accounts.AccountManager
import android.annotation.SuppressLint
import android.content.Context
import android.os.Parcelable
import android.os.UserManager
import android.system.Os import android.system.Os
import androidx.annotation.Keep import androidx.annotation.Keep
import com.bintianqi.owndroid.IUserService import com.bintianqi.owndroid.IUserService
import com.bintianqi.owndroid.getContext
import java.io.BufferedReader import java.io.BufferedReader
import java.io.InputStreamReader import java.io.InputStreamReader
import java.lang.Class
@Keep @Keep
class ShizukuService: IUserService.Stub() { class ShizukuService: IUserService.Stub() {
@@ -33,4 +41,10 @@ class ShizukuService: IUserService.Stub() {
} }
override fun getUid(): Int = Os.getuid() override fun getUid(): Int = Os.getuid()
@SuppressLint("MissingPermission")
override fun listAccounts(): Array<Account> {
val am = getContext().getSystemService(Context.ACCOUNT_SERVICE) as AccountManager
return am.accounts
}
} }

View File

@@ -122,7 +122,7 @@
<string name="activate_device_owner">Активировать владельца устройства</string> <string name="activate_device_owner">Активировать владельца устройства</string>
<string name="activate_org_profile">Активировать рабочий профиль, принадлежащий организации</string> <string name="activate_org_profile">Активировать рабочий профиль, принадлежащий организации</string>
<string name="shizuku_service_disconnected">Служба Shizuku отключена</string> <string name="shizuku_service_disconnected">Служба Shizuku отключена</string>
<string name="accounts">Accounts</string> <!--TODO-->
<!--Системные--> <!--Системные-->
<string name="system">Syetem</string> <!--TODO--> <string name="system">Syetem</string> <!--TODO-->

View File

@@ -124,6 +124,7 @@
<string name="activate_device_owner">Cihaz Sahibini Etkinleştir</string> <string name="activate_device_owner">Cihaz Sahibini Etkinleştir</string>
<string name="activate_org_profile">Kuruluş Profili Sahibini Etkinleştir</string> <string name="activate_org_profile">Kuruluş Profili Sahibini Etkinleştir</string>
<string name="shizuku_service_disconnected">Shizuku Hizmeti Bağlantısı Kesildi</string> <string name="shizuku_service_disconnected">Shizuku Hizmeti Bağlantısı Kesildi</string>
<string name="accounts">Accounts</string> <!--TODO-->
<!--System--> <!--System-->
<string name="system">Sistem</string> <string name="system">Sistem</string>

View File

@@ -118,6 +118,7 @@
<string name="activate_device_owner">激活Device owner</string> <string name="activate_device_owner">激活Device owner</string>
<string name="activate_org_profile">激活由组织拥有的工作资料</string> <string name="activate_org_profile">激活由组织拥有的工作资料</string>
<string name="shizuku_service_disconnected">Shizuku服务断开连接</string> <string name="shizuku_service_disconnected">Shizuku服务断开连接</string>
<string name="accounts">账号</string>
<!--System--> <!--System-->
<string name="system">系统</string> <string name="system">系统</string>
@@ -661,7 +662,7 @@
<string name="info_security_log">设备上不能有非附属用户</string> <string name="info_security_log">设备上不能有非附属用户</string>
<string name="info_pre_reboot_security_log">并非所有设备都支持重启前安全日志</string> <string name="info_pre_reboot_security_log">并非所有设备都支持重启前安全日志</string>
<string name="info_disable_account_management">当某个帐户类型的帐户管理被禁用时,将无法添加或删除该类型的帐户。</string> <string name="info_disable_account_management">当某个帐户类型的帐户管理被禁用时,将无法添加或删除该类型的帐户。</string>
<string name="info_frp_policy">恢复出厂设置保护(Factory reset protection)策略用于防止不受信任的重置(Fastboot或Recovery)。需要设备支持持久数据块服务(Persistent data block service)</string> <string name="info_frp_policy">恢复出厂设置保护(Factory reset protection)策略决定哪些帐户可以解锁经过不受信任的恢复出厂设置(fastboot或recovery)的设备。\n要启用此功能设备必须支持持久数据块服务(Persistent data block service)。\n如果在开发者选项中启用了OEM解锁则FRP将被禁用。</string>
<string name="info_wipe_data_in_managed_user">此用户的所有数据将会被清除,但是用户不会被删除。</string> <string name="info_wipe_data_in_managed_user">此用户的所有数据将会被清除,但是用户不会被删除。</string>
<string name="info_lockdown_admin_configured_network">控制用户是否可以更改管理员配置的网络。启用此锁定后用户仍然可以配置和连接到其他Wi-Fi或使用其他Wi-Fi功能如网络共享</string> <string name="info_lockdown_admin_configured_network">控制用户是否可以更改管理员配置的网络。启用此锁定后用户仍然可以配置和连接到其他Wi-Fi或使用其他Wi-Fi功能如网络共享</string>
<string name="info_minimum_wifi_security_level">指定Wi-Fi网络所需的最低安全等级。设备将无法连接到低于最低安全等级的网络。如果当前网络不满足要求则会断开连接。</string> <string name="info_minimum_wifi_security_level">指定Wi-Fi网络所需的最低安全等级。设备将无法连接到低于最低安全等级的网络。如果当前网络不满足要求则会断开连接。</string>

View File

@@ -127,10 +127,10 @@
<string name="list_accounts">List accounts</string> <string name="list_accounts">List accounts</string>
<string name="shizuku_not_started">Shizuku not started. </string> <string name="shizuku_not_started">Shizuku not started. </string>
<string name="dpm_activate_do_command" translatable="false">dpm set-device-owner com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver</string> <string name="dpm_activate_do_command" translatable="false">dpm set-device-owner com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver</string>
<string name="dpm_activate_da_command" translatable="false">dpm set-active-admin com.bintianqi.owndroid/com.bintianqi.owndroid.Receiver</string>
<string name="activate_device_owner">Activate Device owner</string> <string name="activate_device_owner">Activate Device owner</string>
<string name="activate_org_profile">Activate organization-owned work profile</string> <string name="activate_org_profile">Activate organization-owned work profile</string>
<string name="shizuku_service_disconnected">Shizuku service disconnected</string> <string name="shizuku_service_disconnected">Shizuku service disconnected</string>
<string name="accounts">Accounts</string>
<!--System--> <!--System-->
<string name="system">System</string> <string name="system">System</string>
@@ -701,7 +701,7 @@
<string name="info_security_log">If a Device owner use this function, all users should be affiliated.</string> <string name="info_security_log">If a Device owner use this function, all users should be affiliated.</string>
<string name="info_pre_reboot_security_log">Not all devices support pre-reboot security logs.</string> <string name="info_pre_reboot_security_log">Not all devices support pre-reboot security logs.</string>
<string name="info_disable_account_management">When account management is disabled for an account type, adding or removing an account of that type will not be possible.</string> <string name="info_disable_account_management">When account management is disabled for an account type, adding or removing an account of that type will not be possible.</string>
<string name="info_frp_policy">Factory reset protection can protect the device after untrusted factory reset (in Recovery or Fastboot).\nTo enable this feature, the device must support persistent data block service.</string> <string name="info_frp_policy">The factory reset protection policy determines which accounts can unlock a device that has gone through untrusted factory reset(fastboot or recovery).\nTo enable this feature, the device must support persistent data block service.\nFactory reset protection is disabled if OEM unlocking is enabled in Developer Options.</string>
<string name="info_wipe_data_in_managed_user">All data of this user will be wiped, but that user won\'t be removed.</string> <string name="info_wipe_data_in_managed_user">All data of this user will be wiped, but that user won\'t be removed.</string>
<string name="info_lockdown_admin_configured_network">Control whether the user can change networks configured by the admin.\nWhen this lockdown is enabled, the user can still configure and connect to other Wi-Fi networks, or use other Wi-Fi capabilities such as tethering.</string> <string name="info_lockdown_admin_configured_network">Control whether the user can change networks configured by the admin.\nWhen this lockdown is enabled, the user can still configure and connect to other Wi-Fi networks, or use other Wi-Fi capabilities such as tethering.</string>
<string name="info_minimum_wifi_security_level">Specify the minimum security level required for Wi-Fi networks. The device may not connect to networks that do not meet the minimum security level. If the current network does not meet the minimum security level set, it will be disconnected.</string> <string name="info_minimum_wifi_security_level">Specify the minimum security level required for Wi-Fi networks. The device may not connect to networks that do not meet the minimum security level. If the current network does not meet the minimum security level set, it will be disconnected.</string>