diff --git a/Guide.md b/Guide.md index 07ca65b..49242b9 100644 --- a/Guide.md +++ b/Guide.md @@ -836,7 +836,7 @@ Profile owner无法禁用部分功能,工作资料中部分功能无效,wear - (29) 内容捕获(作用未知) - (29) 内容建议(作用未知) - 创建窗口(比如Toast) -- (24) 更换壁纸 +- (24) 更换壁纸(在MIUI上可能不起作用) - (34) 启用设备管理器(设备管理器就是Device admin) - (23) 娱乐(仅谷歌商店里的应用) - 修改账号设置 diff --git a/app/src/main/java/com/binbin/androidowner/MainActivity.kt b/app/src/main/java/com/binbin/androidowner/MainActivity.kt index e087b84..2074f9b 100644 --- a/app/src/main/java/com/binbin/androidowner/MainActivity.kt +++ b/app/src/main/java/com/binbin/androidowner/MainActivity.kt @@ -125,9 +125,9 @@ fun MyScaffold(){ "UserManage" to R.string.user_manage, "ApplicationManage" to R.string.app_manage, "UserRestriction" to R.string.user_restrict, - "Password" to R.string.password, + "Password" to R.string.password_and_keyguard, "AppSetting" to R.string.setting, - "ShizukuActivate" to R.string.shizuku_activate + "ShizukuActivate" to R.string.shizuku ) val topBarName = topBarNameMap[backStackEntry?.destination?.route]?: R.string.app_name val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE) @@ -245,7 +245,7 @@ fun HomePage(navCtrl:NavHostController){ HomePageItem(R.string.app_manage, R.drawable.apps_fill0, "ApplicationManage", navCtrl) HomePageItem(R.string.user_restrict, R.drawable.manage_accounts_fill0, "UserRestriction", navCtrl) HomePageItem(R.string.user_manage,R.drawable.account_circle_fill0,"UserManage",navCtrl) - HomePageItem(R.string.password, R.drawable.password_fill0, "Password",navCtrl) + HomePageItem(R.string.password_and_keyguard, R.drawable.password_fill0, "Password",navCtrl) HomePageItem(R.string.setting, R.drawable.info_fill0, "AppSetting",navCtrl) Spacer(Modifier.padding(vertical = 20.dp)) } diff --git a/app/src/main/java/com/binbin/androidowner/ManagedProfile.kt b/app/src/main/java/com/binbin/androidowner/ManagedProfile.kt index a5f90b7..d031697 100644 --- a/app/src/main/java/com/binbin/androidowner/ManagedProfile.kt +++ b/app/src/main/java/com/binbin/androidowner/ManagedProfile.kt @@ -27,6 +27,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp @@ -45,19 +46,19 @@ fun ManagedProfile() { Column(modifier = Modifier.verticalScroll(rememberScrollState())){ Column(modifier = sections()){ - Text(text = "信息", style = typography.titleLarge, color = titleColor) + Text(text = stringResource(R.string.info), style = typography.titleLarge, color = titleColor) if(VERSION.SDK_INT>=24){ if(isProfileOwner(myDpm)&&myDpm.isManagedProfile(myComponent)){ - Text(text = "已是工作资料") + Text(text = stringResource(R.string.is_already_work_profile)) }else{ - Text(text = "可以创建工作资料:${myDpm.isProvisioningAllowed(ACTION_PROVISION_MANAGED_PROFILE)}", style = bodyTextStyle) + Text(text = stringResource(R.string.able_to_create_work_profile, myDpm.isProvisioningAllowed(ACTION_PROVISION_MANAGED_PROFILE)), style = bodyTextStyle) if(isDeviceOwner(myDpm)){ - Text(text = "Device owner不能创建工作资料", style = bodyTextStyle) + Text(text = stringResource(R.string.device_owner_cannot_create_work_profile), style = bodyTextStyle) } } } if(VERSION.SDK_INT>=30){ - Text(text = "由组织拥有的工作资料:${myDpm.isOrganizationOwnedDeviceWithManagedProfile}", style = bodyTextStyle) + Text(text = stringResource(R.string.is_org_owned_profile, myDpm.isOrganizationOwnedDeviceWithManagedProfile), style = bodyTextStyle) } if(VERSION.SDK_INT<24||(VERSION.SDK_INT>=24&&isProfileOwner(myDpm)&&myDpm.isManagedProfile(myComponent))){ Button( @@ -80,26 +81,25 @@ fun ManagedProfile() { var expand by remember{mutableStateOf(false)} Column(modifier = sections(colorScheme.tertiaryContainer,{expand=true},!expand).animateContentSize(animationSpec = scrollAnim())){ if(expand){ - Text(text = "组织拥有的工作资料", color = colorScheme.onTertiaryContainer, style = typography.titleLarge) + Text(text = stringResource(R.string.org_owned_work_profile), color = colorScheme.onTertiaryContainer, style = typography.titleLarge) SelectionContainer { Text(text = "使用ADB执行以下命令,或者使用Shizuku") Text( - text = "adb shell \"dpm mark-profile-owner-on-organization-owned-device --user ${Binder.getCallingUid()/100000}" + - " com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver\"", + text = stringResource(R.string.activate_org_profile_command, Binder.getCallingUid()/100000), color = colorScheme.onTertiaryContainer, style = bodyTextStyle ) } }else{ - Text(text = "成为组织拥有的工作资料", color = colorScheme.onTertiaryContainer) - Text(text = "点击展开", style = bodyTextStyle) + Text(text = stringResource(R.string.become_org_profile), color = colorScheme.onTertiaryContainer) + Text(text = stringResource(R.string.touch_to_view_command), style = bodyTextStyle) } } } if(VERSION.SDK_INT<24||(VERSION.SDK_INT>=24&&myDpm.isProvisioningAllowed(ACTION_PROVISION_MANAGED_PROFILE))){ Column(modifier = sections()) { - Text(text = "工作资料", style = typography.titleLarge, color = titleColor) + Text(text = stringResource(R.string.work_profile), style = typography.titleLarge, color = titleColor) var skipEncrypt by remember{mutableStateOf(false)} - if(VERSION.SDK_INT>=24){CheckBoxItem("跳过加密",{skipEncrypt},{skipEncrypt=!skipEncrypt})} + if(VERSION.SDK_INT>=24){CheckBoxItem(stringResource(R.string.skip_encryption),{skipEncrypt},{skipEncrypt=!skipEncrypt})} Button( onClick = { try { @@ -113,12 +113,12 @@ fun ManagedProfile() { if(VERSION.SDK_INT>=33){intent.putExtra(EXTRA_PROVISIONING_ALLOW_OFFLINE,true)} createManagedProfile.launch(intent) }catch(e:ActivityNotFoundException){ - Toast.makeText(myContext,"不支持",Toast.LENGTH_SHORT).show() + Toast.makeText(myContext,myContext.getString(R.string.unsupported),Toast.LENGTH_SHORT).show() } }, modifier = Modifier.fillMaxWidth() ) { - Text("创建") + Text(stringResource(R.string.create)) } } } @@ -127,7 +127,7 @@ fun ManagedProfile() { Row(modifier = sections(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically){ var suspended by remember{mutableStateOf(false)} suspended = myDpm.getPersonalAppsSuspendedReasons(myComponent)!=PERSONAL_APPS_NOT_SUSPENDED - Text(text = "挂起个人应用", style = typography.titleLarge, color = titleColor) + Text(text = stringResource(R.string.suspend_personal_app), style = typography.titleLarge, color = titleColor) Switch( checked = suspended, onCheckedChange ={ @@ -142,24 +142,24 @@ fun ManagedProfile() { Column(modifier = sections()){ var time by remember{mutableStateOf("")} time = myDpm.getManagedProfileMaximumTimeOff(myComponent).toString() - Text(text = "资料关闭时间", style = typography.titleLarge, color = titleColor) - Text(text = "工作资料处于关闭状态的时间达到该限制后会挂起个人应用,0为无限制", style = bodyTextStyle) - Text(text = "个人应用已经因此挂起:${myDpm.getPersonalAppsSuspendedReasons(myComponent)==PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT}") + Text(text = stringResource(R.string.profile_max_time_off), style = typography.titleLarge, color = titleColor) + Text(text = stringResource(R.string.profile_max_time_out_desc), style = bodyTextStyle) + Text(text = stringResource(R.string.personal_app_suspended_because_timeout, myDpm.getPersonalAppsSuspendedReasons(myComponent)==PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT)) OutlinedTextField( value = time, onValueChange = {time=it}, modifier = Modifier.focusable().fillMaxWidth().padding(vertical = 2.dp), - label = {Text("时间(ms)")}, + label = {Text(stringResource(R.string.time_unit_ms))}, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}) ) - Text(text = "不能少于72小时", style = bodyTextStyle) + Text(text = stringResource(R.string.cannot_less_than_72_hours), style = bodyTextStyle) Button( onClick = { myDpm.setManagedProfileMaximumTimeOff(myComponent,time.toLong()) - Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.success), Toast.LENGTH_SHORT).show() }, modifier = Modifier.fillMaxWidth() ) { - Text("应用") + Text(stringResource(R.string.apply)) } } } @@ -167,7 +167,7 @@ fun ManagedProfile() { if(isProfileOwner(myDpm)&&(VERSION.SDK_INT<24||(VERSION.SDK_INT>=24&&myDpm.isManagedProfile(myComponent)))){ Column(modifier = sections()){ var action by remember{mutableStateOf("")} - Text(text = "Intent过滤器", style = typography.titleLarge, color = titleColor) + Text(text = stringResource(R.string.intent_filter), style = typography.titleLarge, color = titleColor) OutlinedTextField( value = action, onValueChange = {action = it}, label = {Text("Action")}, @@ -178,31 +178,31 @@ fun ManagedProfile() { Button( onClick = { myDpm.addCrossProfileIntentFilter(myComponent, IntentFilter(action), FLAG_PARENT_CAN_ACCESS_MANAGED) - Toast.makeText(myContext,"成功",Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.success),Toast.LENGTH_SHORT).show() }, modifier = Modifier.fillMaxWidth() ) { - Text("添加(工作到个人)") + Text(stringResource(R.string.add_intent_filter_work_to_personal)) } Button( onClick = { myDpm.addCrossProfileIntentFilter(myComponent, IntentFilter(action), FLAG_MANAGED_CAN_ACCESS_PARENT) - Toast.makeText(myContext,"成功",Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.success),Toast.LENGTH_SHORT).show() }, modifier = Modifier.fillMaxWidth() ) { - Text("添加(个人到工作)") + Text(stringResource(R.string.add_intent_filter_personal_to_work)) } Button( onClick = { myDpm.clearCrossProfileIntentFilters(myComponent) myDpm.addCrossProfileIntentFilter(myComponent, IntentFilter("com.binbin.androidowner.MAIN_ACTION"), FLAG_MANAGED_CAN_ACCESS_PARENT) myDpm.addCrossProfileIntentFilter(myComponent, IntentFilter("com.binbin.androidowner.MAIN_ACTION"), FLAG_PARENT_CAN_ACCESS_MANAGED) - Toast.makeText(myContext,"成功",Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.success),Toast.LENGTH_SHORT).show() }, modifier = Modifier.fillMaxWidth() ){ - Text("清除所有过滤器") + Text(stringResource(R.string.clear_cross_profile_filters)) } } } @@ -210,28 +210,28 @@ fun ManagedProfile() { if(VERSION.SDK_INT>=31&&(isProfileOwner(myDpm)&&myDpm.isManagedProfile(myComponent))){ Column(modifier = sections()){ var orgId by remember{mutableStateOf("")} - Text(text = "组织ID", style = typography.titleLarge, color = titleColor) + Text(text = stringResource(R.string.org_id), style = typography.titleLarge, color = titleColor) OutlinedTextField( value = orgId, onValueChange = {orgId=it}, - label = {Text("组织ID")}, + label = {Text(stringResource(R.string.org_id))}, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Ascii, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), modifier = Modifier.focusable().fillMaxWidth().padding(vertical = 2.dp) ) AnimatedVisibility(orgId.length !in 6..64) { - Text(text = "长度应在6~64个字符之间", style = bodyTextStyle) + Text(text = stringResource(R.string.length_6_to_64), style = bodyTextStyle) } Button( onClick = { myDpm.setOrganizationId(orgId) - Toast.makeText(myContext,"成功",Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.success),Toast.LENGTH_SHORT).show() }, enabled = orgId.length in 6..64, modifier = Modifier.fillMaxWidth() ){ - Text("应用") + Text(stringResource(R.string.apply)) } - Text(text = "设置组织ID后才能获取设备唯一标识码", style = bodyTextStyle) + Text(text = stringResource(R.string.get_specific_id_after_set_org_id), style = bodyTextStyle) } } @@ -248,18 +248,18 @@ fun ActivateManagedProfile(navCtrl: NavHostController){ myDpm.addCrossProfileIntentFilter(myComponent, IntentFilter("com.binbin.androidowner.MAIN_ACTION"), FLAG_MANAGED_CAN_ACCESS_PARENT) myDpm.addCrossProfileIntentFilter(myComponent, IntentFilter("com.binbin.androidowner.MAIN_ACTION"), FLAG_PARENT_CAN_ACCESS_MANAGED) Column(modifier = Modifier.verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally){ - Text(text = "激活工作资料", style = typography.titleLarge) - Text(text = "你还没有激活工作资料,请立即激活") + Text(text = stringResource(R.string.activate_managed_profile), style = typography.titleLarge) + Text(text = stringResource(R.string.activate_managed_profile_desc)) Button( onClick = { myDpm.setProfileEnabled(myComponent) navCtrl.popBackStack("HomePage",false) sharedPref.edit().putBoolean("ManagedProfileActivated",true).apply() - Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.success), Toast.LENGTH_SHORT).show() }, modifier = Modifier.fillMaxWidth().padding(8.dp) ) { - Text("激活") + Text(stringResource(R.string.activate)) } } } diff --git a/app/src/main/java/com/binbin/androidowner/Network.kt b/app/src/main/java/com/binbin/androidowner/Network.kt index 618df10..654fbaf 100644 --- a/app/src/main/java/com/binbin/androidowner/Network.kt +++ b/app/src/main/java/com/binbin/androidowner/Network.kt @@ -74,8 +74,8 @@ fun Network(){ if(VERSION.SDK_INT>=33){ Column(modifier = sections()){ var selectedWifiSecLevel by remember{mutableIntStateOf(myDpm.minimumRequiredWifiSecurityLevel)} - Text(text = "要求最小WiFi安全等级", style = typography.titleLarge, color = titleColor) - RadioButtonItem("开放", {selectedWifiSecLevel==DevicePolicyManager.WIFI_SECURITY_OPEN}, {selectedWifiSecLevel= DevicePolicyManager.WIFI_SECURITY_OPEN}) + Text(text = stringResource(R.string.min_wifi_security_level), style = typography.titleLarge, color = titleColor) + RadioButtonItem(stringResource(R.string.wifi_security_level_open), {selectedWifiSecLevel==DevicePolicyManager.WIFI_SECURITY_OPEN}, {selectedWifiSecLevel= DevicePolicyManager.WIFI_SECURITY_OPEN}) RadioButtonItem("WEP, WPA(2)-PSK", {selectedWifiSecLevel==DevicePolicyManager.WIFI_SECURITY_PERSONAL}, {selectedWifiSecLevel= DevicePolicyManager.WIFI_SECURITY_PERSONAL}) RadioButtonItem("WPA-EAP", {selectedWifiSecLevel==DevicePolicyManager.WIFI_SECURITY_ENTERPRISE_EAP}, {selectedWifiSecLevel= DevicePolicyManager.WIFI_SECURITY_ENTERPRISE_EAP}) RadioButtonItem("WPA3-192bit", {selectedWifiSecLevel==DevicePolicyManager.WIFI_SECURITY_ENTERPRISE_192}, {selectedWifiSecLevel= DevicePolicyManager.WIFI_SECURITY_ENTERPRISE_192}) @@ -83,15 +83,13 @@ fun Network(){ enabled = isDeviceOwner(myDpm)||(isProfileOwner(myDpm)&&myDpm.isOrganizationOwnedDeviceWithManagedProfile), onClick = { myDpm.minimumRequiredWifiSecurityLevel=selectedWifiSecLevel - Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.success), Toast.LENGTH_SHORT).show() }, modifier = Modifier.fillMaxWidth() ){ - Text("应用") + Text(stringResource(R.string.apply)) } } - }else{ - Text(text = "Wifi安全等级需API33", modifier = Modifier.padding(vertical = 3.dp)) } if(VERSION.SDK_INT>=33&&(isDeviceOwner(myDpm)||(isProfileOwner(myDpm)&&myDpm.isOrganizationOwnedDeviceWithManagedProfile))){ @@ -112,13 +110,13 @@ fun Network(){ } var inited by remember{mutableStateOf(false)} if(!inited){ refreshPolicy(); refreshList(); inited=true } - Text(text = "WiFi SSID策略", style = typography.titleLarge, color = titleColor) - RadioButtonItem("无",{selectedPolicyType==-1},{selectedPolicyType=-1}) - RadioButtonItem("白名单",{selectedPolicyType==WIFI_SSID_POLICY_TYPE_ALLOWLIST},{selectedPolicyType=WIFI_SSID_POLICY_TYPE_ALLOWLIST}) - RadioButtonItem("黑名单",{selectedPolicyType==WIFI_SSID_POLICY_TYPE_DENYLIST},{selectedPolicyType=WIFI_SSID_POLICY_TYPE_DENYLIST}) + Text(text = stringResource(R.string.wifi_ssid_policy), style = typography.titleLarge, color = titleColor) + RadioButtonItem(stringResource(R.string.none),{selectedPolicyType==-1},{selectedPolicyType=-1}) + RadioButtonItem(stringResource(R.string.whitelist),{selectedPolicyType==WIFI_SSID_POLICY_TYPE_ALLOWLIST},{selectedPolicyType=WIFI_SSID_POLICY_TYPE_ALLOWLIST}) + RadioButtonItem(stringResource(R.string.blacklist),{selectedPolicyType==WIFI_SSID_POLICY_TYPE_DENYLIST},{selectedPolicyType=WIFI_SSID_POLICY_TYPE_DENYLIST}) Column(modifier = Modifier.animateContentSize(scrollAnim()).horizontalScroll(rememberScrollState())){ if(ssidList!=""){ - Text("SSID列表:") + Text(stringResource(R.string.ssid_list_is)) SelectionContainer{ Text(text = ssidList, style = bodyTextStyle, color = colorScheme.onPrimaryContainer) } @@ -136,9 +134,9 @@ fun Network(){ Button( onClick = { if(inputSsid==""){ - Toast.makeText(myContext, "不能为空", Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.cannot_be_empty), Toast.LENGTH_SHORT).show() }else if(WifiSsid.fromBytes(inputSsid.toByteArray()) in ssidSet){ - Toast.makeText(myContext, "重复", Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.already_exist), Toast.LENGTH_SHORT).show() }else{ ssidSet.add(WifiSsid.fromBytes(inputSsid.toByteArray())) refreshList() @@ -147,23 +145,23 @@ fun Network(){ }, modifier = Modifier.fillMaxWidth(0.49F) ) { - Text("添加") + Text(stringResource(R.string.add)) } Button( onClick = { if(inputSsid==""){ - Toast.makeText(myContext, "不能为空", Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.cannot_be_empty), Toast.LENGTH_SHORT).show() }else if(WifiSsid.fromBytes(inputSsid.toByteArray()) in ssidSet){ ssidSet.remove(WifiSsid.fromBytes(inputSsid.toByteArray())) inputSsid = "" refreshList() }else{ - Toast.makeText(myContext, "不存在", Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.not_exist), Toast.LENGTH_SHORT).show() } }, modifier = Modifier.fillMaxWidth(0.96F) ) { - Text("移除") + Text(stringResource(R.string.remove)) } } Button( @@ -171,16 +169,16 @@ fun Network(){ focusMgr.clearFocus() if(selectedPolicyType==-1){ if(policy==null&&ssidSet.isNotEmpty()){ - Toast.makeText(myContext, "请选择策略", Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.please_select_a_policy), Toast.LENGTH_SHORT).show() }else{ myDpm.wifiSsidPolicy = null refreshPolicy() - Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.success), Toast.LENGTH_SHORT).show() } }else{ myDpm.wifiSsidPolicy = if(ssidSet.size==0){ null }else{ WifiSsidPolicy(selectedPolicyType, ssidSet) } refreshPolicy() - Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.success), Toast.LENGTH_SHORT).show() } }, modifier = Modifier.fillMaxWidth() @@ -191,20 +189,20 @@ fun Network(){ } if(VERSION.SDK_INT>=29&&isDeviceOwner(myDpm)){ Column(modifier = sections()){ - Text(text = "私人DNS", style = typography.titleLarge, color = titleColor) + Text(text = stringResource(R.string.private_dns), style = typography.titleLarge, color = titleColor) val dnsStatus = mapOf( - DevicePolicyManager.PRIVATE_DNS_MODE_UNKNOWN to "未知", - DevicePolicyManager.PRIVATE_DNS_MODE_OFF to "关闭", - DevicePolicyManager.PRIVATE_DNS_MODE_OPPORTUNISTIC to "自动", - DevicePolicyManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME to "指定主机名" + DevicePolicyManager.PRIVATE_DNS_MODE_UNKNOWN to stringResource(R.string.unknown), + DevicePolicyManager.PRIVATE_DNS_MODE_OFF to stringResource(R.string.disabled), + DevicePolicyManager.PRIVATE_DNS_MODE_OPPORTUNISTIC to stringResource(R.string.auto), + DevicePolicyManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME to stringResource(R.string.dns_provide_hostname) ) val operationResult = mapOf( - DevicePolicyManager.PRIVATE_DNS_SET_NO_ERROR to "成功", - DevicePolicyManager.PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING to "主机不支持DNS over TLS", - DevicePolicyManager.PRIVATE_DNS_SET_ERROR_FAILURE_SETTING to "失败" + DevicePolicyManager.PRIVATE_DNS_SET_NO_ERROR to stringResource(R.string.success), + DevicePolicyManager.PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING to stringResource(R.string.host_not_serving_dns_tls), + DevicePolicyManager.PRIVATE_DNS_SET_ERROR_FAILURE_SETTING to stringResource(R.string.fail) ) var status by remember{mutableStateOf(dnsStatus[myDpm.getGlobalPrivateDnsMode(myComponent)])} - Text(text = "当前状态:$status") + Text(text = stringResource(R.string.current_state, status?:stringResource(R.string.unknown))) Button( onClick = { val result = myDpm.setGlobalPrivateDnsModeOpportunistic(myComponent) @@ -213,14 +211,14 @@ fun Network(){ }, modifier = Modifier.fillMaxWidth() ) { - Text("设为自动") + Text(stringResource(R.string.set_to_auto)) } Spacer(Modifier.padding(vertical = 3.dp)) var inputHost by remember{mutableStateOf(myDpm.getGlobalPrivateDnsHost(myComponent) ?: "")} OutlinedTextField( value = inputHost, onValueChange = {inputHost=it}, - label = {Text("DNS主机名")}, + label = {Text(stringResource(R.string.dns_hostname))}, keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), modifier = Modifier.focusable().fillMaxWidth().padding(vertical = 2.dp) @@ -233,27 +231,27 @@ fun Network(){ result = myDpm.setGlobalPrivateDnsModeSpecifiedHost(myComponent,inputHost) Toast.makeText(myContext, operationResult[result], Toast.LENGTH_SHORT).show() }catch(e:IllegalArgumentException){ - Toast.makeText(myContext, "无效主机名", Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.invalid_hostname), Toast.LENGTH_SHORT).show() }catch(e:SecurityException){ - Toast.makeText(myContext, "安全错误", Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.security_exception), Toast.LENGTH_SHORT).show() }finally { status = dnsStatus[myDpm.getGlobalPrivateDnsMode(myComponent)] } }, modifier = Modifier.fillMaxWidth() ) { - Text("设置DNS主机") + Text(stringResource(R.string.set_dns_host)) } } } if(VERSION.SDK_INT>=26&&(isDeviceOwner(myDpm)||(isProfileOwner(myDpm)&&myDpm.isManagedProfile(myComponent)))){ Column(modifier = sections()){ - Text(text = "收集网络日志", style = typography.titleLarge, color = titleColor) - Text(text = "功能开发中", style = bodyTextStyle) + Text(text = stringResource(R.string.retrieve_net_logs), style = typography.titleLarge, color = titleColor) + Text(text = stringResource(R.string.developing), style = bodyTextStyle) Row(modifier=Modifier.fillMaxWidth().padding(horizontal=8.dp),horizontalArrangement=Arrangement.SpaceBetween,verticalAlignment=Alignment.CenterVertically){ var checked by remember{mutableStateOf(myDpm.isNetworkLoggingEnabled(myComponent))} - Text(text = "启用", style = typography.titleLarge) + Text(text = stringResource(R.string.enabled), style = typography.titleLarge) Switch( checked = checked, onCheckedChange = {myDpm.setNetworkLoggingEnabled(myComponent,!checked);checked = myDpm.isNetworkLoggingEnabled(myComponent)} @@ -264,15 +262,15 @@ fun Network(){ val log = myDpm.retrieveNetworkLogs(myComponent,1234567890) if(log!=null){ for(i in log){ Log.d("NetLog",i.toString()) } - Toast.makeText(myContext,"已输出至Log",Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.success),Toast.LENGTH_SHORT).show() }else{ - Log.d("NetLog","无") - Toast.makeText(myContext,"无",Toast.LENGTH_SHORT).show() + Log.d("NetLog",myContext.getString(R.string.none)) + Toast.makeText(myContext, myContext.getString(R.string.none),Toast.LENGTH_SHORT).show() } }, modifier = Modifier.fillMaxWidth() ) { - Text("收集") + Text(stringResource(R.string.retrieve)) } } } @@ -280,35 +278,35 @@ fun Network(){ if(VERSION.SDK_INT>=31&&(isDeviceOwner(myDpm)||isProfileOwner(myDpm))){ Column(modifier = sections()){ var keyPair by remember{mutableStateOf("")} - Text(text = "WiFi密钥对", style = typography.titleLarge, color = titleColor) + Text(text = stringResource(R.string.wifi_keypair), style = typography.titleLarge, color = titleColor) OutlinedTextField( value = keyPair, - label = { Text("密钥对")}, + label = { Text(stringResource(R.string.keypair))}, onValueChange = {keyPair = it}, keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), modifier = Modifier.focusable().fillMaxWidth().padding(vertical = 2.dp) ) val isExist = try{myDpm.isKeyPairGrantedToWifiAuth(keyPair)}catch(e:java.lang.IllegalArgumentException){false} - Text("已存在:$isExist") + Text(stringResource(R.string.already_exist)+":$isExist") Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween){ Button( onClick = { val result = myDpm.grantKeyPairToWifiAuth(keyPair) - Toast.makeText(myContext, if(result){"成功"}else{"失败"}, Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(if(result){R.string.success}else{R.string.fail}), Toast.LENGTH_SHORT).show() }, modifier = Modifier.fillMaxWidth(0.49F) ) { - Text("添加") + Text(stringResource(R.string.add)) } Button( onClick = { val result = myDpm.revokeKeyPairFromWifiAuth(keyPair) - Toast.makeText(myContext, if(result){"成功"}else{"失败"}, Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(if(result){R.string.success}else{R.string.fail}), Toast.LENGTH_SHORT).show() }, modifier = Modifier.fillMaxWidth(0.96F) ) { - Text("移除") + Text(stringResource(R.string.remove)) } } } @@ -320,17 +318,17 @@ fun Network(){ var inputNum by remember{mutableStateOf("0")} var nextStep by remember{mutableStateOf(false)} val builder = Builder() - Text(text = "APN设置", style = typography.titleLarge, color = titleColor) + Text(text = stringResource(R.string.apn_settings), style = typography.titleLarge, color = titleColor) Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically){ - Text(text = "启用", style = typography.titleLarge) + Text(text = stringResource(R.string.enable), style = typography.titleLarge) Switch(checked = myDpm.isOverrideApnEnabled(myComponent), onCheckedChange = {myDpm.setOverrideApnsEnabled(myComponent,it)}) } - Text(text = "一共有${setting.size}个APN设置", style = bodyTextStyle) + Text(text = stringResource(R.string.total_apn_amount, setting.size), style = bodyTextStyle) if(setting.size>0){ - Text(text = "选择一个你要修改的APN设置(1~${setting.size})或者输入0以新建APN设置", style = bodyTextStyle) + Text(text = stringResource(R.string.select_a_apn_or_create, setting.size), style = bodyTextStyle) TextField( value = inputNum, - label = { Text("序号")}, + label = { Text("APN")}, onValueChange = {inputNum = it}, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), @@ -338,14 +336,14 @@ fun Network(){ enabled = !nextStep ) }else{ - Text(text = "当前没有APN设置,你可以新建一个APN设置", style = bodyTextStyle) + Text(text = stringResource(R.string.no_apn_you_should_create_one), style = bodyTextStyle) } Button( onClick = {focusMgr.clearFocus(); nextStep=!nextStep}, modifier = Modifier.fillMaxWidth(), enabled = inputNum!=""&&(nextStep||inputNum=="0"||setting[inputNum.toInt()-1]!=null) ) { - Text(if(nextStep){"上一步"}else{"下一步"}) + Text(stringResource(if(nextStep){R.string.previous_step}else{R.string.next_step})) } var result = Builder().build() AnimatedVisibility(nextStep) { @@ -404,28 +402,28 @@ fun Network(){ TextField( value = inputApnName, onValueChange = {inputApnName=it}, - label = {Text("名称")}, + label = {Text(stringResource(R.string.name))}, keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), modifier = Modifier.focusable().fillMaxWidth().padding(top = 2.dp, bottom = 4.dp) ) Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically){ - Text(text = "启用", style = typography.titleLarge) + Text(text = stringResource(R.string.enable), style = typography.titleLarge) Switch(checked = carrierEnabled, onCheckedChange = {carrierEnabled=it}) } - Text(text = "用户名", style = typography.titleLarge) + Text(text = stringResource(R.string.user_name), style = typography.titleLarge) TextField( value = user, onValueChange = {user=it}, - label = {Text("用户名")}, + label = {Text(stringResource(R.string.user_name))}, keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), modifier = Modifier.focusable().fillMaxWidth().padding(top = 2.dp, bottom = 4.dp) ) if(VERSION.SDK_INT>=33){ - Text(text = "资料ID", style = typography.titleLarge) + Text(text = stringResource(R.string.profile_id), style = typography.titleLarge) TextField( value = profileId, onValueChange = {profileId=it}, @@ -436,7 +434,7 @@ fun Network(){ ) } - Text(text = "验证类型", style = typography.titleLarge) + Text(text = stringResource(R.string.auth_type), style = typography.titleLarge) RadioButtonItem("无",{selectedAuthType==AUTH_TYPE_NONE},{selectedAuthType=AUTH_TYPE_NONE}) RadioButtonItem("CHAP",{selectedAuthType==AUTH_TYPE_CHAP},{selectedAuthType=AUTH_TYPE_CHAP}) RadioButtonItem("PAP",{selectedAuthType==AUTH_TYPE_PAP},{selectedAuthType=AUTH_TYPE_PAP}) @@ -456,32 +454,32 @@ fun Network(){ ) } - Text(text = "APN类型", style = typography.titleLarge) + Text(text = stringResource(R.string.apn_type), style = typography.titleLarge) TextField( value = apnTypeBitmask, onValueChange = {apnTypeBitmask=it}, - label = {Text("位掩码")}, + label = {Text(stringResource(R.string.bitmask))}, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), modifier = Modifier.focusable().fillMaxWidth().padding(top = 2.dp, bottom = 4.dp) ) - Text(text = "描述", style = typography.titleLarge) + Text(text = stringResource(R.string.description), style = typography.titleLarge) TextField( value = entryName, onValueChange = {entryName=it}, - label = {Text("文本")}, + label = {Text(stringResource(R.string.description))}, keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), modifier = Modifier.focusable().fillMaxWidth().padding(top = 2.dp, bottom = 4.dp) ) - Text(text = "MMS代理", style = typography.titleLarge) + Text(text = stringResource(R.string.mms_proxy), style = typography.titleLarge) if(VERSION.SDK_INT>=29){ TextField( value = mmsProxyAddress, onValueChange = {mmsProxyAddress=it}, - label = {Text("地址")}, + label = {Text(stringResource(R.string.address))}, keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), modifier = Modifier.focusable().fillMaxWidth().padding(top = 2.dp, bottom = 4.dp) @@ -490,18 +488,18 @@ fun Network(){ TextField( value = mmsProxyPort, onValueChange = {mmsProxyPort=it}, - label = {Text("端口")}, + label = {Text(stringResource(R.string.port))}, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), modifier = Modifier.focusable().fillMaxWidth().padding(top = 2.dp, bottom = 4.dp) ) - Text(text = "代理", style = typography.titleLarge) + Text(text = stringResource(R.string.proxy), style = typography.titleLarge) if(VERSION.SDK_INT>=29){ TextField( value = proxyAddress, onValueChange = {proxyAddress=it}, - label = {Text("地址")}, + label = {Text(stringResource(R.string.address))}, keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), modifier = Modifier.focusable().fillMaxWidth().padding(top = 2.dp, bottom = 4.dp) @@ -510,7 +508,7 @@ fun Network(){ TextField( value = proxyPort, onValueChange = {proxyPort=it}, - label = {Text("端口")}, + label = {Text(stringResource(R.string.port))}, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), modifier = Modifier.focusable().fillMaxWidth().padding(top = 2.dp, bottom = 4.dp) @@ -552,11 +550,11 @@ fun Network(){ RadioButtonItem("GID",{mvnoType==MVNO_TYPE_GID},{mvnoType=MVNO_TYPE_GID}) RadioButtonItem("ICCID",{mvnoType==MVNO_TYPE_ICCID},{mvnoType=MVNO_TYPE_ICCID}) - Text(text = "网络类型", style = typography.titleLarge) + Text(text = stringResource(R.string.network_type), style = typography.titleLarge) TextField( value = networkTypeBitmask, onValueChange = {networkTypeBitmask=it}, - label = {Text("位掩码")}, + label = {Text(stringResource(R.string.bitmask))}, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), modifier = Modifier.focusable().fillMaxWidth().padding(top = 2.dp, bottom = 4.dp) @@ -572,11 +570,11 @@ fun Network(){ modifier = Modifier.focusable().fillMaxWidth().padding(top = 2.dp, bottom = 4.dp) ) - Text(text = "密码", style = typography.titleLarge) + Text(text = stringResource(R.string.password), style = typography.titleLarge) TextField( value = password, onValueChange = {password=it}, - label = {Text("密码")}, + label = {Text(stringResource(R.string.password))}, keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), modifier = Modifier.focusable().fillMaxWidth().padding(top = 2.dp, bottom = 4.dp) @@ -584,12 +582,12 @@ fun Network(){ if(VERSION.SDK_INT>=33){ Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically){ - Text(text = "持久的", style = typography.titleLarge) + Text(text = stringResource(R.string.persistent), style = typography.titleLarge) Switch(checked = persistent, onCheckedChange = {persistent=it}) } } - Text(text = "协议", style = typography.titleLarge) + Text(text = stringResource(R.string.protocol), style = typography.titleLarge) RadioButtonItem("IPV4",{protocol==PROTOCOL_IP},{protocol=PROTOCOL_IP}) RadioButtonItem("IPV6",{protocol==PROTOCOL_IPV6},{protocol=PROTOCOL_IPV6}) RadioButtonItem("IPV4/IPV6",{protocol==PROTOCOL_IPV4V6},{protocol=PROTOCOL_IPV4V6}) @@ -599,7 +597,7 @@ fun Network(){ RadioButtonItem("Unstructured",{protocol==PROTOCOL_UNSTRUCTURED},{protocol=PROTOCOL_UNSTRUCTURED}) } - Text(text = "漫游协议", style = typography.titleLarge) + Text(text = stringResource(R.string.roaming_protocol), style = typography.titleLarge) RadioButtonItem("IPV4",{roamingProtocol==PROTOCOL_IP},{roamingProtocol=PROTOCOL_IP}) RadioButtonItem("IPV6",{roamingProtocol==PROTOCOL_IPV6},{roamingProtocol=PROTOCOL_IPV6}) RadioButtonItem("IPV4/IPV6",{roamingProtocol==PROTOCOL_IPV4V6},{roamingProtocol=PROTOCOL_IPV4V6}) @@ -641,7 +639,7 @@ fun Network(){ }, modifier = Modifier.fillMaxWidth() ) { - Text(if(finalStep){"上一步"}else{"下一步"}) + Text(stringResource(if(finalStep){R.string.previous_step}else{R.string.next_step})) } AnimatedVisibility(finalStep) { if(inputNum=="0"){ @@ -649,18 +647,18 @@ fun Network(){ onClick = {myDpm.addOverrideApn(myComponent,result)}, modifier = Modifier.fillMaxWidth() ) { - Text("新建") + Text(stringResource(R.string.create)) } }else{ Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween){ Button( onClick = { val success = myDpm.updateOverrideApn(myComponent,id,result) - Toast.makeText(myContext, if(success){"成功"}else{"失败"}, Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(if(success){R.string.success}else{R.string.fail}), Toast.LENGTH_SHORT).show() }, Modifier.fillMaxWidth(0.49F) ){ - Text("更新") + Text(stringResource(R.string.update)) } Button( onClick = { @@ -669,7 +667,7 @@ fun Network(){ }, Modifier.fillMaxWidth(0.96F) ){ - Text("移除") + Text(stringResource(R.string.remove)) } } } diff --git a/app/src/main/java/com/binbin/androidowner/Password.kt b/app/src/main/java/com/binbin/androidowner/Password.kt index 3db204b..fc92d6b 100644 --- a/app/src/main/java/com/binbin/androidowner/Password.kt +++ b/app/src/main/java/com/binbin/androidowner/Password.kt @@ -52,14 +52,14 @@ fun Password(){ ) { val myByteArray by remember{ mutableStateOf(byteArrayOf(1,1,4,5,1,4,1,9,1,9,8,1,0,1,1,4,5,1,4,1,9,1,9,8,1,0,1,1,4,5,1,4,1,9,1,9,8,1,0)) } Text( - text = "以下操作可能会造成不可挽回的损失,请先备份好数据。执行操作时一定要谨慎!!!", + text = stringResource(R.string.password_warning), color = colorScheme.onErrorContainer, modifier = sections(colorScheme.errorContainer), style=bodyTextStyle ) if(isWear){ Text( - text = "警告!手表不支持带字母的密码,也不支持超过4位的PIN码!如果你设置了这样的密码(或密码复杂度要求),你将无法解锁你的手表!", + text = stringResource(R.string.password_wearos_warning), color = colorScheme.onErrorContainer, modifier = sections(colorScheme.errorContainer), style = typography.bodyMedium @@ -69,88 +69,87 @@ fun Password(){ Column(modifier = sections()) { if(VERSION.SDK_INT>=29){ val passwordComplexity = mapOf( - PASSWORD_COMPLEXITY_NONE to "无(允许不设密码)", - PASSWORD_COMPLEXITY_LOW to "低(允许图案和连续性)", - PASSWORD_COMPLEXITY_MEDIUM to "中(无连续性,至少4位)", - PASSWORD_COMPLEXITY_HIGH to "高(无连续性,至少6位)" + PASSWORD_COMPLEXITY_NONE to stringResource(R.string.password_complexity_none), + PASSWORD_COMPLEXITY_LOW to stringResource(R.string.password_complexity_low), + PASSWORD_COMPLEXITY_MEDIUM to stringResource(R.string.password_complexity_medium), + PASSWORD_COMPLEXITY_HIGH to stringResource(R.string.password_complexity_high) ) val pwdComplex = passwordComplexity[myDpm.passwordComplexity] - Text(text = "当前密码复杂度:$pwdComplex",style=bodyTextStyle) + Text(text = stringResource(R.string.current_password_complexity_is, pwdComplex?:stringResource(R.string.unknown)),style=bodyTextStyle) } if(isDeviceOwner(myDpm)|| isProfileOwner(myDpm)){ - Text("密码达到要求:${myDpm.isActivePasswordSufficient}",style=bodyTextStyle) + Text(stringResource(R.string.is_password_sufficient, myDpm.isActivePasswordSufficient),style=bodyTextStyle) } val pwdFailedAttempts = myDpm.currentFailedPasswordAttempts - Text(text = "密码已错误次数:$pwdFailedAttempts",style=bodyTextStyle) + Text(text = stringResource(R.string.password_failed_attempts_is, pwdFailedAttempts),style=bodyTextStyle) if(VERSION.SDK_INT>=28&&isProfileOwner(myDpm)&&myDpm.isManagedProfile(myComponent)){ val unifiedPwd = myDpm.isUsingUnifiedPassword(myComponent) - Text("个人与工作应用密码一致:$unifiedPwd",style=bodyTextStyle) + Text(stringResource(R.string.is_using_unified_password, unifiedPwd),style=bodyTextStyle) } } } if(VERSION.SDK_INT>=26){ Column(horizontalAlignment = Alignment.Start, modifier = sections()) { - Text(text = "密码重置令牌", style = typography.titleLarge,color = titleColor) + Text(text = stringResource(R.string.reset_password_token), style = typography.titleLarge,color = titleColor) Row( modifier = if(!isWear){Modifier.fillMaxWidth()}else{Modifier.horizontalScroll(rememberScrollState())}, horizontalArrangement = Arrangement.SpaceBetween ){ Button( onClick = { - if(myDpm.clearResetPasswordToken(myComponent)){ Toast.makeText(myContext, "清除成功", Toast.LENGTH_SHORT).show() - }else{ Toast.makeText(myContext, "清除失败", Toast.LENGTH_SHORT).show() } + if(myDpm.clearResetPasswordToken(myComponent)){ Toast.makeText(myContext, myContext.getString(R.string.success), Toast.LENGTH_SHORT).show() + }else{ Toast.makeText(myContext, myContext.getString(R.string.fail), Toast.LENGTH_SHORT).show() } }, modifier = if(isWear){Modifier}else{Modifier.fillMaxWidth(0.32F)}, enabled = isDeviceOwner(myDpm)||isProfileOwner(myDpm) ) { - Text("清除") + Text(stringResource(R.string.clear)) } if(isWear){Spacer(Modifier.padding(horizontal = 2.dp))} Button( onClick = { try { if(myDpm.setResetPasswordToken(myComponent, myByteArray)){ - Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.success), Toast.LENGTH_SHORT).show() }else{ - Toast.makeText(myContext, "失败", Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.fail), Toast.LENGTH_SHORT).show() } }catch(e:SecurityException){ - Toast.makeText(myContext, "失败(安全异常)", Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.security_exception), Toast.LENGTH_SHORT).show() } }, enabled = isDeviceOwner(myDpm)||isProfileOwner(myDpm), modifier = if(isWear){Modifier}else{Modifier.fillMaxWidth(0.47F)} ) { - Text("设置") + Text(stringResource(R.string.set)) } if(isWear){Spacer(Modifier.padding(horizontal = 2.dp))} Button( onClick = { if(!myDpm.isResetPasswordTokenActive(myComponent)){ - try{ activateToken(myContext) - }catch(e:NullPointerException){ Toast.makeText(myContext, "请先设置令牌", Toast.LENGTH_SHORT).show() } + try{ activateToken(myContext) } + catch(e:NullPointerException){ Toast.makeText(myContext, myContext.getString(R.string.please_set_a_token), Toast.LENGTH_SHORT).show() } }else{ Toast.makeText(myContext, "已经激活", Toast.LENGTH_SHORT).show() } }, enabled = isDeviceOwner(myDpm)||isProfileOwner(myDpm), modifier = if(isWear){Modifier}else{Modifier.fillMaxWidth(0.88F)} ) { - Text("激活") + Text(stringResource(R.string.activate)) } } - if(isWear){ Text(text = "(可以水平滚动)",style=typography.bodyMedium) } - Text("没有密码时会自动激活令牌",style=bodyTextStyle) + Text(stringResource(R.string.activate_token_not_required_when_no_password),style=bodyTextStyle) } } Column( modifier = sections() ) { var confirmed by remember{ mutableStateOf(false) } - Text(text = "修改密码",style = typography.titleLarge,color = titleColor) + Text(text = stringResource(R.string.reset_password),style = typography.titleLarge,color = titleColor) OutlinedTextField( value = newPwd, onValueChange = {newPwd=it}, enabled = !confirmed&&(isDeviceOwner(myDpm)||isProfileOwner(myDpm)||myDpm.isAdminActive(myComponent)), - label = { Text("密码")}, + label = { Text(stringResource(R.string.password))}, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), modifier = Modifier.focusable().padding(vertical = if(isWear){0.dp}else{5.dp}).fillMaxWidth() @@ -158,14 +157,17 @@ fun Password(){ Text(text = stringResource(R.string.reset_pwd_desc), modifier = Modifier.padding(vertical = 3.dp),style=bodyTextStyle) var resetPwdFlag by remember{ mutableIntStateOf(0) } if(VERSION.SDK_INT>=23){ - RadioButtonItem("启动(boot)时不要求密码", {resetPwdFlag==RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT}, {resetPwdFlag=RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT}) + RadioButtonItem( + stringResource(R.string.do_not_ask_credentials_on_boot), + {resetPwdFlag==RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT}, {resetPwdFlag=RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT} + ) } - RadioButtonItem("不允许其他设备管理员重置密码直至用户输入一次密码",{resetPwdFlag==RESET_PASSWORD_REQUIRE_ENTRY}, {resetPwdFlag=RESET_PASSWORD_REQUIRE_ENTRY}) - RadioButtonItem("无",{resetPwdFlag==0},{resetPwdFlag=0}) + RadioButtonItem(stringResource(R.string.reset_password_require_entry),{resetPwdFlag==RESET_PASSWORD_REQUIRE_ENTRY}, {resetPwdFlag=RESET_PASSWORD_REQUIRE_ENTRY}) + RadioButtonItem(stringResource(R.string.none),{resetPwdFlag==0},{resetPwdFlag=0}) Button( onClick = { if(newPwd.length>=4||newPwd.isEmpty()){ confirmed=!confirmed - }else{ Toast.makeText(myContext, "需要4位密码", Toast.LENGTH_SHORT).show() } + }else{ Toast.makeText(myContext, myContext.getString(R.string.require_4_digit_password), Toast.LENGTH_SHORT).show() } }, enabled = isDeviceOwner(myDpm) || isProfileOwner(myDpm) || myDpm.isAdminActive(myComponent), modifier = Modifier.fillMaxWidth(), @@ -174,35 +176,35 @@ fun Password(){ contentColor = if(confirmed){ colorScheme.onPrimary }else{ colorScheme.onError } ) ) { - Text(text = if(confirmed){"取消"}else{"确定"}) + Text(text = stringResource(if(confirmed){R.string.cancel}else{R.string.confirm})) } if(VERSION.SDK_INT>=26){ Button( onClick = { val resetSuccess = myDpm.resetPasswordWithToken(myComponent,newPwd,myByteArray,resetPwdFlag) - if(resetSuccess){ Toast.makeText(myContext, "设置成功", Toast.LENGTH_SHORT).show();newPwd=""} - else{ Toast.makeText(myContext, "设置失败", Toast.LENGTH_SHORT).show() } + if(resetSuccess){ Toast.makeText(myContext, myContext.getString(R.string.success), Toast.LENGTH_SHORT).show();newPwd=""} + else{ Toast.makeText(myContext, myContext.getString(R.string.fail), Toast.LENGTH_SHORT).show() } confirmed=false }, colors = ButtonDefaults.buttonColors(containerColor = colorScheme.error, contentColor = colorScheme.onError), enabled = confirmed&&(isDeviceOwner(myDpm)||isProfileOwner(myDpm)), modifier = Modifier.fillMaxWidth() ) { - Text("使用令牌重置密码") + Text(stringResource(R.string.reset_password_with_token)) } } Button( onClick = { val resetSuccess = myDpm.resetPassword(newPwd,resetPwdFlag) - if(resetSuccess){ Toast.makeText(myContext, "设置成功", Toast.LENGTH_SHORT).show();newPwd=""} - else{ Toast.makeText(myContext, "设置失败", Toast.LENGTH_SHORT).show() } + if(resetSuccess){ Toast.makeText(myContext, myContext.getString(R.string.success), Toast.LENGTH_SHORT).show(); newPwd=""} + else{ Toast.makeText(myContext, myContext.getString(R.string.fail), Toast.LENGTH_SHORT).show() } confirmed=false }, enabled = confirmed, colors = ButtonDefaults.buttonColors(containerColor = colorScheme.error, contentColor = colorScheme.onError), modifier = Modifier.fillMaxWidth() ) { - Text("重置密码(弃用)") + Text(stringResource(R.string.reset_password_deprecated)) } } @@ -212,23 +214,22 @@ fun Password(){ {myDpm.getPasswordExpiration(null).toString()},{ic -> myDpm.setPasswordExpirationTimeout(myComponent, ic.toLong()) }) PasswordItem(R.string.pwd_history,R.string.pwd_history_desc,R.string.pwd_history_textfield,true, {myDpm.getPasswordHistoryLength(null).toString()},{ic -> myDpm.setPasswordHistoryLength(myComponent, ic.toInt()) }) - PasswordItem(R.string.max_time_to_lock,R.string.max_time_to_lock_desc,R.string.max_time_to_lock_textfield,true, + PasswordItem(R.string.max_time_to_lock,R.string.max_time_to_lock_desc,R.string.time_unit_ms,true, {myDpm.getMaximumTimeToLock(myComponent).toString()},{ic -> myDpm.setMaximumTimeToLock(myComponent,ic.toLong())}) if(VERSION.SDK_INT>=31){ Column(modifier = sections()) { val passwordComplexity = mapOf( - PASSWORD_COMPLEXITY_NONE to "无(允许不设密码)", - PASSWORD_COMPLEXITY_LOW to "低(允许图案和连续性)", - PASSWORD_COMPLEXITY_MEDIUM to "中(无连续性,至少4位)", - PASSWORD_COMPLEXITY_HIGH to "高(无连续性,至少6位)" + PASSWORD_COMPLEXITY_NONE to stringResource(R.string.password_complexity_none), + PASSWORD_COMPLEXITY_LOW to stringResource(R.string.password_complexity_low), + PASSWORD_COMPLEXITY_MEDIUM to stringResource(R.string.password_complexity_medium), + PASSWORD_COMPLEXITY_HIGH to stringResource(R.string.password_complexity_high) ).toList() var selectedItem by remember{ mutableIntStateOf(passwordComplexity[0].first) } if(isDeviceOwner(myDpm) || isProfileOwner(myDpm)){ selectedItem=myDpm.requiredPasswordComplexity } - Text(text = "密码复杂度要求", style = typography.titleLarge,color = titleColor) - Text(text = "不是实际密码复杂度", style = bodyTextStyle) + Text(text = stringResource(R.string.required_password_complexity), style = typography.titleLarge,color = titleColor) RadioButtonItem(passwordComplexity[0].second,{selectedItem==passwordComplexity[0].first},{selectedItem=passwordComplexity[0].first}) RadioButtonItem(passwordComplexity[1].second,{selectedItem==passwordComplexity[1].first},{selectedItem=passwordComplexity[1].first}) RadioButtonItem(passwordComplexity[2].second,{selectedItem==passwordComplexity[2].first},{selectedItem=passwordComplexity[2].first}) @@ -236,24 +237,24 @@ fun Password(){ if(isWear){ colorScheme.error}else{ colorScheme.onBackground}) - Text(text = "连续性:密码重复(6666)或密码递增递减(4321、2468)", modifier = Modifier.padding(vertical = 3.dp), style = bodyTextStyle) + Text(text = stringResource(R.string.password_ordered_desc), modifier = Modifier.padding(vertical = 3.dp), style = bodyTextStyle) Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.SpaceBetween){ Button( onClick = { myDpm.requiredPasswordComplexity = selectedItem - Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.success), Toast.LENGTH_SHORT).show() }, enabled = isDeviceOwner(myDpm)|| isProfileOwner(myDpm), modifier = if(isWear){Modifier.fillMaxWidth()}else{Modifier.fillMaxWidth(0.4F)} ) { - Text(text = "应用") + Text(text = stringResource(R.string.apply)) } if(!isWear){ Button( onClick = {myContext.startActivity(Intent(ACTION_SET_NEW_PASSWORD))}, modifier = Modifier.fillMaxWidth(0.95F) ){ - Text("要求设置新密码") + Text(stringResource(R.string.require_set_new_password)) } } } @@ -262,7 +263,7 @@ fun Password(){ onClick = {myContext.startActivity(Intent(ACTION_SET_NEW_PASSWORD))}, modifier = Modifier.fillMaxWidth() ){ - Text("要求设置新密码") + Text(stringResource(R.string.require_set_new_password)) } } } @@ -306,25 +307,25 @@ fun Password(){ } calculateCustomFeature() } - Text(text = "锁屏功能", style = typography.titleLarge) - RadioButtonItem("允许全部",{state==0},{state=0}) - RadioButtonItem("禁用全部",{state==1},{state=1}) - RadioButtonItem("自定义",{state==2},{state=2}) + Text(text = stringResource(R.string.keyguard_disabled_features), style = typography.titleLarge) + RadioButtonItem(stringResource(R.string.enable_all),{state==0},{state=0}) + RadioButtonItem(stringResource(R.string.disable_all),{state==1},{state=1}) + RadioButtonItem(stringResource(R.string.custom),{state==2},{state=2}) AnimatedVisibility(state==2) { Column { - CheckBoxItem("禁用小工具(安卓5以下)",{widgets},{widgets=!widgets}) - CheckBoxItem("禁用相机",{camera},{camera=!camera}) - CheckBoxItem("禁用通知",{notification},{notification=!notification}) - CheckBoxItem("禁用未经编辑的通知",{unredacted},{unredacted=!unredacted}) - CheckBoxItem("禁用可信代理",{agents},{agents=!agents}) - CheckBoxItem("禁用指纹解锁",{fingerprint},{fingerprint=!fingerprint}) - if(VERSION.SDK_INT>=24){ CheckBoxItem("禁止远程输入(弃用)",{remote}, {remote=!remote}) } + CheckBoxItem(stringResource(R.string.keyguard_disabled_features_widgets),{widgets},{widgets=!widgets}) + CheckBoxItem(stringResource(R.string.keyguard_disabled_features_camera),{camera},{camera=!camera}) + CheckBoxItem(stringResource(R.string.keyguard_disabled_features_notification),{notification},{notification=!notification}) + CheckBoxItem(stringResource(R.string.keyguard_disabled_features_unredacted_notification),{unredacted},{unredacted=!unredacted}) + CheckBoxItem(stringResource(R.string.keyguard_disabled_features_trust_agents),{agents},{agents=!agents}) + CheckBoxItem(stringResource(R.string.keyguard_disabled_features_fingerprint),{fingerprint},{fingerprint=!fingerprint}) + if(VERSION.SDK_INT>=24){ CheckBoxItem(stringResource(R.string.keyguard_disabled_features_remote_input),{remote}, {remote=!remote}) } if(VERSION.SDK_INT>=28){ - CheckBoxItem("禁用人脸解锁",{face},{face=!face}) - CheckBoxItem("禁用虹膜解锁(?)",{iris},{iris=!iris}) - CheckBoxItem("禁用生物识别",{biometrics},{biometrics=!biometrics}) + CheckBoxItem(stringResource(R.string.keyguard_disabled_features_face),{face},{face=!face}) + CheckBoxItem(stringResource(R.string.keyguard_disabled_features_iris),{iris},{iris=!iris}) + CheckBoxItem(stringResource(R.string.keyguard_disabled_features_biometrics),{biometrics},{biometrics=!biometrics}) } - if(VERSION.SDK_INT>=34){ CheckBoxItem("禁用快捷方式",{shortcuts},{shortcuts=!shortcuts}) } + if(VERSION.SDK_INT>=34){ CheckBoxItem(stringResource(R.string.keyguard_disabled_features_shortcuts),{shortcuts},{shortcuts=!shortcuts}) } } } Button( @@ -346,13 +347,13 @@ fun Password(){ if(widgets){result+=KEYGUARD_DISABLE_WIDGETS_ALL} } myDpm.setKeyguardDisabledFeatures(myComponent,result) - Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.success), Toast.LENGTH_SHORT).show() calculateCustomFeature() }, enabled = isDeviceOwner(myDpm)||isProfileOwner(myDpm), modifier = Modifier.fillMaxWidth() ) { - Text(text = "应用") + Text(text = stringResource(R.string.apply)) } } @@ -367,23 +368,22 @@ fun Password(){ } Column(modifier = sections(onClick = {passwordQualityExpand=true;launchScrollDown=true}, clickable = !passwordQualityExpand).animateContentSize(animationSpec = scrollAnim())) { val passwordQuality = mapOf( - PASSWORD_QUALITY_UNSPECIFIED to "未指定", - PASSWORD_QUALITY_SOMETHING to "需要密码或图案,不管复杂度", - PASSWORD_QUALITY_ALPHABETIC to "至少1个字母", - PASSWORD_QUALITY_NUMERIC to "至少1个数字", - PASSWORD_QUALITY_ALPHANUMERIC to "数字字母各至少一个", - PASSWORD_QUALITY_BIOMETRIC_WEAK to "生物识别(弱)", - PASSWORD_QUALITY_NUMERIC_COMPLEX to "复杂数字(无连续性)", - PASSWORD_QUALITY_COMPLEX to "自定义(暂不支持)", + PASSWORD_QUALITY_UNSPECIFIED to stringResource(R.string.password_quality_unspecified), + PASSWORD_QUALITY_SOMETHING to stringResource(R.string.password_quality_something), + PASSWORD_QUALITY_ALPHABETIC to stringResource(R.string.password_quality_alphabetic), + PASSWORD_QUALITY_NUMERIC to stringResource(R.string.password_quality_numeric), + PASSWORD_QUALITY_ALPHANUMERIC to stringResource(R.string.password_quality_alphanumeric), + PASSWORD_QUALITY_BIOMETRIC_WEAK to stringResource(R.string.password_quality_biometrics_weak), + PASSWORD_QUALITY_NUMERIC_COMPLEX to stringResource(R.string.password_quality_numeric_complex), + PASSWORD_QUALITY_COMPLEX to stringResource(R.string.custom)+"(${stringResource(R.string.unsupported)})", ).toList() var selectedItem by remember{ mutableIntStateOf(passwordQuality[0].first) } if(isDeviceOwner(myDpm) || isProfileOwner(myDpm)){ selectedItem=myDpm.getPasswordQuality(myComponent) } - Text(text = "密码质量要求", style = typography.titleLarge,color = titleColor) + Text(text = stringResource(R.string.required_password_quality), style = typography.titleLarge,color = titleColor) if(passwordQualityExpand){ - Text(text = "不是实际密码质量", style = bodyTextStyle) - Text(text = "设置密码复杂度将会取代密码质量", style = bodyTextStyle) + Text(text = stringResource(R.string.password_complexity_instead_password_quality), style = bodyTextStyle) } - if(VERSION.SDK_INT>=31){ Text(text = "已弃用,请使用上面的”密码复杂度要求“。点击展开", color = colorScheme.error, style = bodyTextStyle) } + if(VERSION.SDK_INT>=31){ Text(text = stringResource(R.string.password_quality_deprecated_desc), color = colorScheme.error, style = bodyTextStyle) } if(passwordQualityExpand){ RadioButtonItem(passwordQuality[0].second,{selectedItem==passwordQuality[0].first},{selectedItem=passwordQuality[0].first}) RadioButtonItem(passwordQuality[1].second,{selectedItem==passwordQuality[1].first},{selectedItem=passwordQuality[1].first}) @@ -393,20 +393,20 @@ fun Password(){ RadioButtonItem(passwordQuality[5].second,{selectedItem==passwordQuality[5].first},{selectedItem=passwordQuality[5].first}) RadioButtonItem(passwordQuality[6].second,{selectedItem==passwordQuality[6].first},{selectedItem=passwordQuality[6].first}) RadioButtonItem(passwordQuality[7].second,{selectedItem==passwordQuality[7].first},{selectedItem=passwordQuality[7].first}) - Text(text = "连续性:密码重复(6666)或密码递增递减(4321、2468)", modifier = Modifier.padding(vertical = 3.dp), style = bodyTextStyle) + Text(text = stringResource(R.string.password_ordered_desc), modifier = Modifier.padding(vertical = 3.dp), style = bodyTextStyle) Button( onClick = { myDpm.setPasswordQuality(myComponent,selectedItem) - Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.success), Toast.LENGTH_SHORT).show() }, enabled = isDeviceOwner(myDpm) || isProfileOwner(myDpm), modifier = Modifier.fillMaxWidth() ) { - Text("应用") + Text(stringResource(R.string.apply)) } if(VERSION.SDK_INT<31){ Button(onClick = {myContext.startActivity(Intent(ACTION_SET_NEW_PASSWORD))}){ - Text("要求设置新密码") + Text(stringResource(R.string.require_set_new_password)) }} } } @@ -465,12 +465,12 @@ private fun PasswordItem( } fun activateToken(myContext: Context){ - val desc = "在这里激活密码重置令牌" + val desc = myContext.getString(R.string.activate_reset_password_token_here) val keyguardManager = myContext.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager - val confirmIntent = keyguardManager.createConfirmDeviceCredentialIntent(null, desc) + val confirmIntent = keyguardManager.createConfirmDeviceCredentialIntent(myContext.getString(R.string.app_name), desc) if (confirmIntent != null) { startActivity(myContext,confirmIntent, null) } else { - Toast.makeText(myContext, "激活失败", Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.fail), Toast.LENGTH_SHORT).show() } } diff --git a/app/src/main/java/com/binbin/androidowner/Setting.kt b/app/src/main/java/com/binbin/androidowner/Setting.kt index 9cc2cbc..124755e 100644 --- a/app/src/main/java/com/binbin/androidowner/Setting.kt +++ b/app/src/main/java/com/binbin/androidowner/Setting.kt @@ -18,6 +18,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.navigation.NavHostController @@ -45,7 +46,7 @@ fun AppSetting(navCtrl:NavHostController){ } if(VERSION.SDK_INT>=32){ Row(modifier = Modifier.fillMaxWidth().padding(horizontal = 3.dp),horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) { - Text(text = "动态取色", style = typography.titleLarge, color = titleColor) + Text(text = stringResource(R.string.dynamic_color), style = typography.titleLarge, color = titleColor) Switch( checked = sharedPref.getBoolean("dynamicColor",false), onCheckedChange = { @@ -54,22 +55,16 @@ fun AppSetting(navCtrl:NavHostController){ } ) } - Text(text = "打开或关闭动态取色需要重启应用", style = if(isWear){typography.bodyMedium}else{typography.bodyLarge}) + Text(text = stringResource(R.string.dynamic_color_desc), style = if(isWear){typography.bodyMedium}else{typography.bodyLarge}) } } Column(modifier = sections()) { Column( modifier = Modifier.padding(start = 8.dp, end = 8.dp, bottom = 12.dp) ) { - Text(text = "关于", style = typography.headlineSmall, color = titleColor) - Text(text = "Android owner v$verName ($verCode)", style = bodyTextStyle) - Text(text = "使用安卓的Device admin、Device owner 、Profile owner,全方位掌控你的设备", style = bodyTextStyle) - Spacer(Modifier.padding(vertical = 4.dp)) - Text(text = "这个应用只在AOSP和LineageOS上测试过,不确保每个功能都在其它系统可用,尤其是国内的魔改系统。", style = bodyTextStyle) - Spacer(Modifier.padding(vertical = 4.dp)) - Text(text = "大部分功能都要Device owner权限", style = bodyTextStyle) - Spacer(Modifier.padding(vertical = 2.dp)) - Text(text = "安卓版本越高,支持的功能越多", style = bodyTextStyle) + Text(text = stringResource(R.string.about), style = typography.headlineSmall, color = titleColor) + Text(text = stringResource(R.string.app_name)+" v$verName ($verCode)", style = bodyTextStyle) + Text(text = stringResource(R.string.about_desc), style = bodyTextStyle) } Row( verticalAlignment = Alignment.CenterVertically, @@ -84,7 +79,7 @@ fun AppSetting(navCtrl:NavHostController){ modifier = Modifier.padding(start = 6.dp, end = 10.dp), tint = colorScheme.primary ) - Text(text = "使用教程", style = typography.titleLarge, color = colorScheme.onPrimaryContainer, modifier = Modifier.padding(bottom = 2.dp)) + Text(text = stringResource(R.string.user_guide), style = typography.titleLarge, color = colorScheme.onPrimaryContainer, modifier = Modifier.padding(bottom = 2.dp)) } Row( verticalAlignment = Alignment.CenterVertically, @@ -99,7 +94,7 @@ fun AppSetting(navCtrl:NavHostController){ modifier = Modifier.padding(start = 6.dp, end = 10.dp), tint = colorScheme.primary ) - Text(text = "源代码", style = typography.titleLarge, color = colorScheme.onPrimaryContainer, modifier = Modifier.padding(bottom = 2.dp)) + Text(text = stringResource(R.string.source_code), style = typography.titleLarge, color = colorScheme.onPrimaryContainer, modifier = Modifier.padding(bottom = 2.dp)) } } Spacer(Modifier.padding(vertical = 30.dp)) @@ -109,5 +104,5 @@ fun AppSetting(navCtrl:NavHostController){ fun shareLink(inputContext:Context,link:String){ val uri = Uri.parse(link) val intent = Intent(Intent.ACTION_VIEW, uri) - inputContext.startActivity(Intent.createChooser(intent, "Hello"),null) + inputContext.startActivity(Intent.createChooser(intent, "Open in browser"),null) } diff --git a/app/src/main/java/com/binbin/androidowner/ShizukuActivate.kt b/app/src/main/java/com/binbin/androidowner/ShizukuActivate.kt index cd3a0a2..d62eaf6 100644 --- a/app/src/main/java/com/binbin/androidowner/ShizukuActivate.kt +++ b/app/src/main/java/com/binbin/androidowner/ShizukuActivate.kt @@ -32,10 +32,10 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp -import kotlinx.coroutines.delay import org.apache.commons.io.IOUtils import rikka.shizuku.Shizuku import java.io.* @@ -58,14 +58,14 @@ fun ShizukuActivate(){ if(Binder.getCallingUid()/100000!=0){ Row(modifier = sections(colorScheme.errorContainer), verticalAlignment = Alignment.CenterVertically){ Icon(imageVector = Icons.Rounded.Warning, contentDescription = null, tint = colorScheme.onErrorContainer) - Text(text = "暂不支持在非主用户中使用Shizuku", style = bodyTextStyle, color = colorScheme.onErrorContainer) + Text(text = stringResource(R.string.not_primary_user_not_support_shizuku), style = bodyTextStyle, color = colorScheme.onErrorContainer) } } var launchPermissionCheck by remember{mutableStateOf(false)} LaunchedEffect(launchPermissionCheck){ if(launchPermissionCheck){ - outputText = checkPermission() + outputText = checkPermission(myContext) scrollState.animateScrollTo(scrollState.maxValue, scrollAnim()) launchPermissionCheck=false } @@ -74,12 +74,12 @@ fun ShizukuActivate(){ onClick = {launchPermissionCheck=true}, enabled = VERSION.SDK_INT>=24, modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp) ) { - Text(text = "检查权限") + Text(text = stringResource(R.string.check_permission)) } if(!isDeviceOwner(myDpm)&&!isProfileOwner(myDpm)){ Column(modifier = sections()){ - Text(text = "激活", style = typography.titleLarge, color = colorScheme.onPrimaryContainer) + Text(text = stringResource(R.string.activate), style = typography.titleLarge, color = colorScheme.onPrimaryContainer) if(!myDpm.isAdminActive(myComponent)){ var launchActivateDA by remember{mutableStateOf(false)} @@ -124,8 +124,8 @@ fun ShizukuActivate(){ if(VERSION.SDK_INT>=30&&!isDeviceOwner(myDpm)&&!myDpm.isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE)&&!myDpm.isOrganizationOwnedDeviceWithManagedProfile){ Column(modifier = sections()){ - Text(text = "组织拥有工作资料", style = typography.titleLarge, color = colorScheme.onPrimaryContainer) - Text(text = "请输入工作资料的UserID", style = bodyTextStyle) + Text(text = stringResource(R.string.org_owned_work_profile), style = typography.titleLarge, color = colorScheme.onPrimaryContainer) + Text(text = stringResource(R.string.input_userid_of_work_profile), style = bodyTextStyle) var inputUserID by remember{mutableStateOf("")} OutlinedTextField( value = inputUserID, onValueChange = {inputUserID=it}, @@ -151,12 +151,12 @@ fun ShizukuActivate(){ onClick = { launchActivateOrgProfile=true if(myDpm.isOrganizationOwnedDeviceWithManagedProfile){ - Toast.makeText(myContext,"成功",Toast.LENGTH_SHORT).show() + Toast.makeText(myContext, myContext.getString(R.string.success),Toast.LENGTH_SHORT).show() } }, modifier = Modifier.fillMaxWidth() ) { - Text(text = "激活") + Text(text = stringResource(R.string.activate)) } } } @@ -172,13 +172,13 @@ fun ShizukuActivate(){ Button( onClick = {launchListOwners=true}, modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp) ) { - Text(text = "列出Owners") + Text(text = stringResource(R.string.list_owners)) } var launchTest by remember{mutableStateOf(false)} LaunchedEffect(launchTest){ if(launchTest){ - outputText="下面应该出现一行包含“2000”或“0”的文本\n" + outputText= myContext.getString(R.string.should_contain_2000_or_0) scrollState.animateScrollTo(scrollState.maxValue, scrollAnim()) outputText+=executeCommand("sh rish.sh","id",null,filesDir) launchTest=false @@ -187,7 +187,7 @@ fun ShizukuActivate(){ Button( onClick = {launchTest=true}, modifier = Modifier.align(Alignment.CenterHorizontally) ) { - Text(text = "测试rish") + Text(text = stringResource(R.string.test_rish)) } SelectionContainer(modifier = Modifier.horizontalScroll(rememberScrollState())){ @@ -220,17 +220,17 @@ fun extractRish(myContext:Context){ if(VERSION.SDK_INT>=34){ Runtime.getRuntime().exec("chmod 400 rish_shizuku.dex",null,myContext.filesDir) } } -private fun checkPermission():String { +private fun checkPermission(myContext: Context):String { return if(Shizuku.isPreV11()) { - "请更新Shizuku" + myContext.getString(R.string.please_update_shizuku) }else{ try{ if(Shizuku.checkSelfPermission()==PackageManager.PERMISSION_GRANTED) { - val permission = when(Shizuku.getUid()){ 0->"Root"; 2000->"Shell"; else->"未知权限" } - "Shizuku v${Shizuku.getVersion()}\n已授权($permission)" - }else if(Shizuku.shouldShowRequestPermissionRationale()){ "用户拒绝" } - else{ Shizuku.requestPermission(0); "请求授权" } - }catch(e: Throwable){ "服务未启动" } + val permission = when(Shizuku.getUid()){ 0->"Root"; 2000->"Shell"; else->myContext.getString(R.string.unknown) } + myContext.getString(R.string.shizuku_permission_granted, Shizuku.getVersion(), permission) + }else if(Shizuku.shouldShowRequestPermissionRationale()){ myContext.getString(R.string.denied) } + else{ Shizuku.requestPermission(0); myContext.getString(R.string.request_permission) } + }catch(e: Throwable){ myContext.getString(R.string.shizuku_not_started) } } } @@ -246,7 +246,7 @@ fun executeCommand(command: String, subCommand:String, env: Array?, dir: IOUtils.copy(tunnel,outputStream) outputStream.close() val exitCode = process.waitFor() - if(exitCode!=0){ result+="出错了!退出码:$exitCode" } + if(exitCode!=0){ result+="Error: $exitCode" } }catch(e:Exception){ e.printStackTrace() return e.toString() diff --git a/app/src/main/java/com/binbin/androidowner/SystemUpdatePolicy.kt b/app/src/main/java/com/binbin/androidowner/SystemUpdatePolicy.kt index 4f5a0de..3d1fcc6 100644 --- a/app/src/main/java/com/binbin/androidowner/SystemUpdatePolicy.kt +++ b/app/src/main/java/com/binbin/androidowner/SystemUpdatePolicy.kt @@ -21,6 +21,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp @@ -43,24 +44,24 @@ fun SysUpdatePolicy(){ Text(text = "Update first available: ${Date(sysUpdateInfo.receivedTime)}", style = bodyTextStyle) Text(text = "Hash code: ${sysUpdateInfo.hashCode()}", style = bodyTextStyle) val securityStateDesc = when(sysUpdateInfo.securityPatchState){ - SystemUpdateInfo.SECURITY_PATCH_STATE_UNKNOWN->"未知" - SystemUpdateInfo.SECURITY_PATCH_STATE_TRUE->"是" - else->"否" + SystemUpdateInfo.SECURITY_PATCH_STATE_UNKNOWN-> stringResource(R.string.unknown) + SystemUpdateInfo.SECURITY_PATCH_STATE_TRUE->"true" + else->"false" } - Text(text = "安全补丁: $securityStateDesc", style = bodyTextStyle) + Text(text = stringResource(R.string.is_security_patch, securityStateDesc), style = bodyTextStyle) }else{ - Text(text = "暂无系统更新", style = bodyTextStyle) + Text(text = stringResource(R.string.no_system_update), style = bodyTextStyle) } } } if(VERSION.SDK_INT>=23){ Column(modifier = sections()) { var selectedPolicy by remember{ mutableStateOf(myDpm.systemUpdatePolicy?.policyType) } - Text(text = "系统更新策略", style = typography.titleLarge, color = colorScheme.onPrimaryContainer) - RadioButtonItem("准备好后立即更新",{selectedPolicy==SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC},{selectedPolicy=SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC}) - RadioButtonItem("在某段时间里更新",{selectedPolicy==SystemUpdatePolicy.TYPE_INSTALL_WINDOWED},{selectedPolicy=SystemUpdatePolicy.TYPE_INSTALL_WINDOWED}) - RadioButtonItem("延迟30天",{selectedPolicy==SystemUpdatePolicy.TYPE_POSTPONE},{selectedPolicy=SystemUpdatePolicy.TYPE_POSTPONE}) - RadioButtonItem("无",{selectedPolicy == null},{selectedPolicy=null}) + Text(text = stringResource(R.string.system_update_policy), style = typography.titleLarge, color = colorScheme.onPrimaryContainer) + RadioButtonItem(stringResource(R.string.system_update_policy_automatic),{selectedPolicy==SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC},{selectedPolicy=SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC}) + RadioButtonItem(stringResource(R.string.system_update_policy_install_windowed),{selectedPolicy==SystemUpdatePolicy.TYPE_INSTALL_WINDOWED},{selectedPolicy=SystemUpdatePolicy.TYPE_INSTALL_WINDOWED}) + RadioButtonItem(stringResource(R.string.system_update_policy_postpone),{selectedPolicy==SystemUpdatePolicy.TYPE_POSTPONE},{selectedPolicy=SystemUpdatePolicy.TYPE_POSTPONE}) + RadioButtonItem(stringResource(R.string.none),{selectedPolicy == null},{selectedPolicy=null}) var windowedPolicyStart by remember{ mutableStateOf("") } var windowedPolicyEnd by remember{ mutableStateOf("") } if(selectedPolicy==2){ @@ -68,7 +69,7 @@ fun SysUpdatePolicy(){ Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.Center) { OutlinedTextField( value = windowedPolicyStart, - label = { Text("开始时间")}, + label = { Text(stringResource(R.string.start_time))}, onValueChange = {windowedPolicyStart=it}, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), @@ -78,14 +79,14 @@ fun SysUpdatePolicy(){ OutlinedTextField( value = windowedPolicyEnd, onValueChange = {windowedPolicyEnd=it}, - label = {Text("结束时间")}, + label = {Text(stringResource(R.string.end_time))}, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), modifier = Modifier.focusable().fillMaxWidth() ) } Spacer(Modifier.padding(vertical = 3.dp)) - Text(text = "请输入一天中的分钟(0~1440)", style = bodyTextStyle) + Text(text = stringResource(R.string.minutes_in_one_day), style = bodyTextStyle) } val policy = when(selectedPolicy){ @@ -99,7 +100,7 @@ fun SysUpdatePolicy(){ enabled = isDeviceOwner(myDpm), modifier = Modifier.fillMaxWidth() ) { - Text("应用") + Text(stringResource(R.string.apply)) } }} /*if(VERSION.SDK_INT>=29){ diff --git a/app/src/main/java/com/binbin/androidowner/UserRestrict.kt b/app/src/main/java/com/binbin/androidowner/UserRestrict.kt index 70010b0..fdb8ce6 100644 --- a/app/src/main/java/com/binbin/androidowner/UserRestrict.kt +++ b/app/src/main/java/com/binbin/androidowner/UserRestrict.kt @@ -78,7 +78,7 @@ fun UserRestriction(){ SectionTab("更多连接",{connectivityVisible}) { connectivityVisible=!connectivityVisible } AnimatedVisibility(connectivityVisible) { Column { - for(connectivityItem in RestrictionData().connectivity()){ + for(connectivityItem in RestrictionData().connectivity(myContext)){ UserRestrictionItem(connectivityItem.restriction,connectivityItem.name,connectivityItem.desc,connectivityItem.ico) } } @@ -86,7 +86,7 @@ fun UserRestriction(){ SectionTab("应用",{applicationVisible}) { applicationVisible=!applicationVisible } AnimatedVisibility(applicationVisible) { Column { - for(applicationItem in RestrictionData().application()){ + for(applicationItem in RestrictionData().application(myContext)){ UserRestrictionItem(applicationItem.restriction,applicationItem.name,applicationItem.desc,applicationItem.ico) } } @@ -110,7 +110,7 @@ fun UserRestriction(){ SectionTab("其他",{otherVisible}) { otherVisible=!otherVisible } AnimatedVisibility(otherVisible) { Column { - for(otherItem in RestrictionData().other()){ + for(otherItem in RestrictionData().other(myContext)){ UserRestrictionItem(otherItem.restriction,otherItem.name,otherItem.desc,otherItem.ico) } } @@ -214,7 +214,7 @@ private class RestrictionData{ if(VERSION.SDK_INT>=24){list += Restriction(UserManager.DISALLOW_DATA_ROAMING,R.string.data_roaming,"",R.drawable.network_cell_fill0)} if(VERSION.SDK_INT>=34){ list += Restriction(UserManager.DISALLOW_CELLULAR_2G,R.string.cellular_2g,"",R.drawable.network_cell_fill0) - list += Restriction(UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO,R.string.ultra_wideband_radio,"",R.drawable.android_fill0) + list += Restriction(UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO,R.string.ultra_wideband_radio,"",R.drawable.wifi_tethering_fill0) } if(VERSION.SDK_INT>=33){ list += Restriction(UserManager.DISALLOW_ADD_WIFI_CONFIG,R.string.add_wifi_conf,"",R.drawable.wifi_fill0) @@ -233,7 +233,7 @@ private class RestrictionData{ list += Restriction(UserManager.DISALLOW_OUTGOING_CALLS,R.string.outgoing_calls,"",R.drawable.phone_forwarded_fill0) return list } - fun connectivity():List{ + fun connectivity(myContext:Context):List{ val list:MutableList = mutableListOf() if(VERSION.SDK_INT>=26){ list += Restriction(UserManager.DISALLOW_BLUETOOTH,R.string.bluetooth,"",R.drawable.bluetooth_fill0) @@ -243,17 +243,17 @@ private class RestrictionData{ if(VERSION.SDK_INT>=28){list += Restriction(UserManager.DISALLOW_CONFIG_LOCATION,R.string.config_location,"",R.drawable.location_on_fill0)} if(VERSION.SDK_INT>=22){list += Restriction(UserManager.DISALLOW_OUTGOING_BEAM,R.string.outgoing_beam,"",R.drawable.nfc_fill0)} list += Restriction(UserManager.DISALLOW_USB_FILE_TRANSFER,R.string.usb_file_transfer,"",R.drawable.usb_fill0) - list += Restriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,R.string.mount_physical_media, "包括TF卡和USB-OTG",R.drawable.sd_card_fill0) + list += Restriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,R.string.mount_physical_media, myContext.getString(R.string.mount_physical_media_desc),R.drawable.sd_card_fill0) if(VERSION.SDK_INT>=28){list += Restriction(UserManager.DISALLOW_PRINTING,R.string.printing,"",R.drawable.print_fill0)} return list } - fun application():List{ + fun application(myContext: Context):List{ val list:MutableList = mutableListOf() list += Restriction(UserManager.DISALLOW_INSTALL_APPS,R.string.install_apps,"",R.drawable.android_fill0) if(VERSION.SDK_INT>=29){list += Restriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY,R.string.install_unknown_src_globally,"",R.drawable.android_fill0)} list += Restriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,R.string.inst_unknown_src,"",R.drawable.android_fill0) list += Restriction(UserManager.DISALLOW_UNINSTALL_APPS,R.string.uninstall_apps,"",R.drawable.delete_fill0) - list += Restriction(UserManager.DISALLOW_APPS_CONTROL,R.string.apps_ctrl, "清空缓存/清空内部存储",R.drawable.apps_fill0) + list += Restriction(UserManager.DISALLOW_APPS_CONTROL,R.string.apps_ctrl, myContext.getString(R.string.apps_control_desc),R.drawable.apps_fill0) if(VERSION.SDK_INT>=34){ list += Restriction(UserManager.DISALLOW_CONFIG_DEFAULT_APPS,R.string.config_default_apps,"",R.drawable.apps_fill0) } return list } @@ -278,14 +278,14 @@ private class RestrictionData{ list += Restriction(UserManager.DISALLOW_REMOVE_USER,R.string.remove_user,"",R.drawable.account_circle_fill0) if(VERSION.SDK_INT>=28){list += Restriction(UserManager.DISALLOW_USER_SWITCH,R.string.switch_user,"",R.drawable.account_circle_fill0)} if(VERSION.SDK_INT>=24){list += Restriction(UserManager.DISALLOW_SET_USER_ICON,R.string.set_user_icon,"",R.drawable.account_circle_fill0)} - list += Restriction(UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE,R.string.cross_profile_copy, "在不同用户和工作资料之间复制粘贴",R.drawable.content_paste_fill0) + list += Restriction(UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE,R.string.cross_profile_copy, "",R.drawable.content_paste_fill0) if(VERSION.SDK_INT>=28){ list += Restriction(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE,R.string.share_into_managed_profile,"",R.drawable.share_fill0) - list += Restriction(UserManager.DISALLOW_UNIFIED_PASSWORD,R.string.unifiied_pwd,"",R.drawable.work_fill0) + list += Restriction(UserManager.DISALLOW_UNIFIED_PASSWORD,R.string.unified_pwd,"",R.drawable.work_fill0) } return list } - fun other():List{ + fun other(myContext: Context):List{ val list:MutableList = mutableListOf() if(VERSION.SDK_INT>=26){ list += Restriction(UserManager.DISALLOW_AUTOFILL,R.string.autofill, "",R.drawable.password_fill0) } list += Restriction(UserManager.DISALLOW_CONFIG_CREDENTIALS,R.string.config_credentials,"",R.drawable.android_fill0) @@ -293,10 +293,10 @@ private class RestrictionData{ list += Restriction(UserManager.DISALLOW_CONTENT_CAPTURE,R.string.content_capture,"",R.drawable.android_fill0) list += Restriction(UserManager.DISALLOW_CONTENT_SUGGESTIONS,R.string.content_suggestions,"",R.drawable.android_fill0) } - list += Restriction(UserManager.DISALLOW_CREATE_WINDOWS,R.string.create_windows, "可能包括Toast和浮动通知",R.drawable.web_asset) + list += Restriction(UserManager.DISALLOW_CREATE_WINDOWS,R.string.create_windows, myContext.getString(R.string.create_windows_desc),R.drawable.web_asset) if(VERSION.SDK_INT>=24){list += Restriction(UserManager.DISALLOW_SET_WALLPAPER,R.string.set_wallpaper,"",R.drawable.wallpaper_fill0)} if(VERSION.SDK_INT>=34){ list += Restriction(UserManager.DISALLOW_GRANT_ADMIN,R.string.grant_admin,"",R.drawable.android_fill0) } - if(VERSION.SDK_INT>=23){ list += Restriction(UserManager.DISALLOW_FUN,R.string.`fun`,"可能会影响谷歌商店的游戏",R.drawable.stadia_controller_fill0) } + if(VERSION.SDK_INT>=23){ list += Restriction(UserManager.DISALLOW_FUN,R.string.`fun`, myContext.getString(R.string.fun_desc),R.drawable.stadia_controller_fill0) } list += Restriction(UserManager.DISALLOW_MODIFY_ACCOUNTS,R.string.modify_accounts,"",R.drawable.manage_accounts_fill0) if(VERSION.SDK_INT>=28){ list += Restriction(UserManager.DISALLOW_CONFIG_LOCALE,R.string.config_locale,"",R.drawable.language_fill0) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bf96e5b..9992877 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,6 +1,6 @@ - Android Owner + Android Owner 禁用 启用 禁用 @@ -24,6 +24,8 @@ 允许 拒绝 当前状态:%1$s + 自动 + 密码 原因 自定义 未知 @@ -35,6 +37,7 @@ 应用 由用户决定 不支持 + 功能开发中 @@ -61,12 +64,31 @@ 把Device owner或Profile owner权限转移到另一个应用。目标必须是Device admin 目标包名 目标类名 + 锁屏信息 + 提供支持的短消息 + 如果你禁用了某个功能,用户尝试使用这个功能时会看见这个消息(可多行) + 消息 + 提供支持的长消息 + 都是显示短消息,长消息不知道在哪里显示 转移 撤销Device admin 撤销Profile owner 撤销Device owner 在这里激活Android Owner + + Shizuku + 暂不支持在非主用户中使用Shizuku + 检查权限 + 请输入工作资料的UserID + 列出Owners + 下面应该出现一行包含“2000”或“0”的文本\n + 测试rish + 请更新Shizuku + Shizuku v%1$i\n已授权(%2$s) + 请求授权 + 服务未启动 + 系统 禁用相机 @@ -127,11 +149,96 @@ 将会删除工作资料 API34或以上将不能在系统用户中使用WipeData + + 安全补丁: %1$s + 暂无系统更新 + 系统更新策略 + 准备好后立即更新 + 在某段时间里更新 + 延迟30天 + 开始时间 + 结束时间 + 请输入一天中的分钟(0~1440) + + + 网络 + 要求最小WiFi安全等级 + 开放 + 优先网络服务 + WiFi锁定 + WiFi SSID策略 + SSID列表: + 不能为空 + 重复 + 请选择策略 + 私人DNS + 指定主机名 + 主机不支持DNS over TLS + 设为自动 + DNS主机名 + 无效主机名 + 安全错误 + 设置DNS主机 + 收集网络日志 + 收集 + WiFi密钥对 + 密钥对 + APN设置 + 一共有%1$s个APN设置 + 选择一个你要修改的APN设置(1~%1$s)或者输入0以新建APN设置 + 当前没有APN设置,你可以新建一个APN设置 + 上一步 + 下一步 + 名称 + 用户名 + 资料ID + 验证类型 + APN类型 + 位掩码 + 描述 + MMS代理 + 地址 + 端口 + 代理 + 网络类型 + 持久的 + 协议 + 漫游协议 + 更新 + + + 工作资料 + 信息 + 已是工作资料 + 可以创建工作资料:%1$s + Device owner不能创建工作资料 + 由组织拥有的工作资料:%1$s + 组织拥有的工作资料 + adb shell \"dpm mark-profile-owner-on-organization-owned-device --user %1$s com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver\" + 成为组织拥有的工作资料 + 跳过加密 + 创建 + 挂起个人应用 + 资料关闭时间 + 工作资料处于关闭状态的时间达到该限制后会挂起个人应用,0为无限制 + 个人应用已经因此挂起:%1$s + 不能少于72小时 + Intent过滤器 + 添加(工作到个人) + 添加(个人到工作) + 清除所有过滤器 + 组织ID + 长度应在6~64个字符之间 + 设置组织ID后才能获取设备唯一标识码 + 激活工作资料 + 你还没有激活工作资料,请立即激活 + 应用管理 挂起 隐藏 如果隐藏,有可能是没安装 + VPN保持打开 权限 作用域: 工作资料 应用详情 @@ -162,98 +269,153 @@ 静默安装 请求安装 + 用户限制 配置移动数据 配置Wi-Fi - 蓝牙 - 蓝牙分享 - 飞行模式 - 配置位置信息 - 调整亮度 - 调试功能 - 创建窗口 - 调整音量 - 安装应用 - 切换摄像头使用权限 - 短信 - 控制应用 - 自动填充服务 - 安装未知来源应用 - 添加用户 - 息屏显示 + 数据漫游 + 使用2G(GSM) + 超宽频段无线电 添加WiFi配置 修改WiFi状态 - 配置小区广播 - 配置凭据 - 修改语言 - 使用2G(GSM) - 修改日期、时间 - 修改默认App - 配置私人DNS - 修改屏幕超时 - 配置网络共享 - 配置VPN - 内容捕获 - 内容建议 - 跨用户复制 - 数据漫游 - 恢复出厂设置 - 娱乐 - 启用设备管理器 - 安装未知来源应用(全局) - 切换麦克风使用权限 - 修改账号设置 - 挂载物理媒体 - 重置网络 - Beam发送 - 拨打电话 - 打印 - 移除用户 - 安全模式 - 修改用户头像 - 更换壁纸 - 分享至工作应用 - 分享位置 - 分享设备管理器配置的WiFi - 系统报错对话框 - 超宽频段无线电 - 个人和工作密码相同 - 卸载应用 - 取消麦克风静音 - USB文件传输 - 切换用户 WiFi直连 WiFi共享 + 分享设备管理器配置的WiFi + 重置网络 + 配置网络共享 + 配置VPN + 配置私人DNS + 飞行模式 + 配置小区广播 + 短信 + 拨出电话 - 密码与锁屏 + 蓝牙 + 蓝牙分享 + 分享位置 + 配置位置信息 + Beam发送 + USB文件传输 + 挂载物理媒体 + 包括TF卡和USB-OTG + 打印 + + 安装应用 + 安装未知来源应用(全局) + 安装未知来源应用 + 卸载应用 + 控制应用 + 清空缓存/清空内部存储 + 修改默认App + + 调整亮度 + 修改屏幕超时 + 息屏显示 + 调整音量 + 取消麦克风静音 + 切换摄像头使用权限 + 切换麦克风使用权限 + + 添加用户 + 移除用户 + 切换用户 + 修改用户头像 + 跨用户复制 + 分享至工作应用 + 个人和工作密码相同 + + 自动填充服务 + 配置凭据 + 内容捕获 + 内容建议 + 创建窗口 + 可能包括Toast和浮动通知 + 更换壁纸 + 启用设备管理器 + 娱乐 + 会影响谷歌商店的游戏 + 修改账号设置 + 修改语言 + 修改日期、时间 + 系统报错对话框 + 恢复出厂设置 + 安全模式 + 调试功能 + + + 用户管理 + + + + 密码与锁屏 留空可以清除密码,纯数字将使用PIN码 最大密码错误次数 达到该限制会恢复出厂设置 错误次数 密码失效超时时间 + 屏幕超时 + 超时后锁屏(毫秒),0为由用户决定 超时后用户需重新设置密码(毫秒),0为无限制 超时时间(ms) 密码历史记录长度 用户输入的密码不能与历史记录中的任何密码相同,0为无限制 历史记录长度 + 以下操作可能会造成不可挽回的损失,请先备份好数据。执行操作时一定要谨慎!!! + 警告!手表不支持带字母的密码,也不支持超过4位的PIN码!如果你设置了这样的密码(或密码复杂度要求),你将无法解锁你的手表! + 无(允许不设密码) + 低(允许图案和连续性) + 中(无连续性,至少4位) + 高(无连续性,至少6位) + 当前密码复杂度:%1$s + 密码达到要求:%1$s + 密码已错误次数:%1$s + 个人与工作应用密码一致:%1$s + 密码重置令牌 + 清除 + 设置 + 请先设置令牌 + 没有密码时会自动激活令牌 + 重置密码 + 启动(boot)时不要求密码 + 不允许其他设备管理员重置密码直至用户输入一次密码 + 需要4位密码 + 使用令牌重置密码 + 重置密码(弃用) + 密码复杂度要求 + 连续性:密码重复(6666)或密码递增递减(4321、2468) + 要求设置新密码 + 锁屏功能 + 启用全部 + 禁用小工具(安卓5以下) + 禁用相机 + 禁用通知 + 禁用未经编辑的通知 + 禁用可信代理 + 禁用指纹解锁 + 禁止远程输入(弃用) + 禁用人脸解锁 + 禁用虹膜解锁(?) + 禁用生物识别 + 禁用快捷方式 + 未指定 + 需要密码或图案,不管复杂度 + 至少1个字母 + 至少1个数字 + 数字字母各至少一个 + 生物识别(弱) + 复杂数字(无连续性) + 密码质量要求 + 设置密码复杂度将会取代密码质量 + 已弃用,请使用上面的”密码复杂度要求“。点击展开 + 在这里激活密码重置令牌 - 锁屏信息 - 提供支持的短消息 - 如果你禁用了某个功能,用户尝试使用这个功能时会看见这个消息(可多行) - 消息 - 提供支持的长消息 - 都是显示短消息,长消息不知道在哪里显示 - 用户管理 + 设置 - VPN保持打开 - 实验性功能 - 屏幕超时 - 超时后锁屏(毫秒),0为由用户决定 - 超时时间(ms) - 优先网络服务 - 网络 - 功能开发中 - WiFi锁定 - 工作资料 - Shizuku + 动态取色 + 打开或关闭动态取色需要重启应用 + 关于 + 使用安卓的Device admin、Device owner 、Profile owner,全方位掌控你的设备 + 使用教程 + 源代码 +