6.7.0 - Alpha11 - 新增 app.isDualInstalled 方法, 用于检测双开应用是否已安装 (需要 Shizuku 或 Root 权限) (issue #450)
This commit is contained in:
@@ -15,6 +15,8 @@ import org.autojs.autojs.annotation.RhinoRuntimeFunctionInterface
|
||||
import org.autojs.autojs.extension.AnyExtensions.isJsNullish
|
||||
import org.autojs.autojs.extension.AnyExtensions.jsBrief
|
||||
import org.autojs.autojs.extension.FlexibleArray
|
||||
import org.autojs.autojs.extension.FlexibleArray.Companion.component1
|
||||
import org.autojs.autojs.extension.FlexibleArray.Companion.component2
|
||||
import org.autojs.autojs.extension.ScriptableExtensions.defineProp
|
||||
import org.autojs.autojs.extension.ScriptableExtensions.deleteProp
|
||||
import org.autojs.autojs.extension.ScriptableExtensions.prop
|
||||
@@ -22,10 +24,14 @@ import org.autojs.autojs.extension.ScriptableObjectExtensions.inquire
|
||||
import org.autojs.autojs.external.receiver.BaseBroadcastReceiver
|
||||
import org.autojs.autojs.ipc.LayoutInspectEventBus
|
||||
import org.autojs.autojs.runtime.ScriptRuntime
|
||||
import org.autojs.autojs.runtime.api.AbstractShell
|
||||
import org.autojs.autojs.runtime.api.AppUtils.Companion.ActivityShortForm
|
||||
import org.autojs.autojs.runtime.api.AppUtils.Companion.BroadcastShortForm
|
||||
import org.autojs.autojs.runtime.api.WrappedShizuku
|
||||
import org.autojs.autojs.runtime.api.augment.Augmentable
|
||||
import org.autojs.autojs.runtime.api.augment.app.App.Companion.ShellAction.Companion.toFallbackShellAction
|
||||
import org.autojs.autojs.runtime.api.augment.app.App.Companion.ShellAction.Companion.toRootShellAction
|
||||
import org.autojs.autojs.runtime.api.augment.app.App.Companion.ShellAction.Companion.toShizukuShellAction
|
||||
import org.autojs.autojs.runtime.api.augment.shell.Shell
|
||||
import org.autojs.autojs.runtime.exception.ShouldNeverHappenException
|
||||
import org.autojs.autojs.runtime.exception.WrappedIllegalArgumentException
|
||||
@@ -82,6 +88,8 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
|
||||
::launchDualSettings.name to AS_GLOBAL,
|
||||
::openAppSetting.name to AS_GLOBAL,
|
||||
::openDualAppSetting.name to AS_GLOBAL,
|
||||
::isInstalled.name to AS_GLOBAL,
|
||||
::isDualInstalled.name to AS_GLOBAL,
|
||||
::uninstall.name to AS_GLOBAL,
|
||||
::uninstallDual.name to AS_GLOBAL,
|
||||
::viewFile.name,
|
||||
@@ -140,14 +148,14 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
|
||||
options is NativeObject -> obj.configure(scriptRuntime, options).let { configuredIntent ->
|
||||
when {
|
||||
checkDualProperty(options) -> startDualActivity(scriptRuntime, args)
|
||||
checkRootProperty(options) && RootUtils.isRootAvailable() -> {
|
||||
val tmpIntent = configuredIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
Shell.execCommand(scriptRuntime, arrayOf<Any>("am start ${intentToShellRhino(tmpIntent)}", /* withRoot = */ true)).throwIfError()
|
||||
}
|
||||
checkShizukuProperty(options) && WrappedShizuku.isOperational() -> {
|
||||
checkShizukuProperty(options) -> {
|
||||
val tmpIntent = configuredIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
WrappedShizuku.execCommand("am start ${intentToShellRhino(tmpIntent)}").throwIfError()
|
||||
}
|
||||
checkRootProperty(options) -> {
|
||||
val tmpIntent = configuredIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
Shell.execCommand(scriptRuntime, arrayOf<Any>("am start ${intentToShellRhino(tmpIntent)}", /* withRoot = */ true)).throwIfError()
|
||||
}
|
||||
else -> startActivityWithGlobalContext(configuredIntent)
|
||||
}
|
||||
}
|
||||
@@ -165,15 +173,15 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
|
||||
}
|
||||
when {
|
||||
checkDualProperty(opt) -> startDualActivity(scriptRuntime, args)
|
||||
checkRootProperty(opt) && RootUtils.isRootAvailable() -> {
|
||||
val tmpIntent = intentRhinoWithRuntime(scriptRuntime, opt).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) }
|
||||
Shell.execCommand(scriptRuntime, arrayOf<Any>("am start ${intentToShellRhino(tmpIntent)}", /* withRoot = */ true)).throwIfError()
|
||||
}
|
||||
checkShizukuProperty(opt) && WrappedShizuku.isOperational() -> {
|
||||
checkShizukuProperty(opt) -> {
|
||||
val tmpIntent = intentRhinoWithRuntime(scriptRuntime, opt).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) }
|
||||
val intentCommand = intentToShellRhino(tmpIntent)
|
||||
WrappedShizuku.execCommand("am start $intentCommand").throwIfError()
|
||||
}
|
||||
checkRootProperty(opt) -> {
|
||||
val tmpIntent = intentRhinoWithRuntime(scriptRuntime, opt).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) }
|
||||
Shell.execCommand(scriptRuntime, arrayOf<Any>("am start ${intentToShellRhino(tmpIntent)}", /* withRoot = */ true)).throwIfError()
|
||||
}
|
||||
else -> startActivityWithGlobalContext(scriptRuntime, opt)
|
||||
}
|
||||
}
|
||||
@@ -775,12 +783,13 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
|
||||
@RhinoRuntimeFunctionInterface
|
||||
fun kill(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Boolean = ensureArgumentsLength(args, 1) { argList ->
|
||||
val packageName = getPackageName(scriptRuntime, argList) ?: return@ensureArgumentsLength false
|
||||
val command = "am force-stop $packageName"
|
||||
when {
|
||||
RootUtils.isRootAvailable() -> Shell.execCommand(scriptRuntime, arrayOf<Any>(command, /* withRoot = */ true))
|
||||
WrappedShizuku.isOperational() -> WrappedShizuku.execCommand(command)
|
||||
else -> Shell.execCommand(scriptRuntime, arrayOf<Any>(command, /* withRoot = */ false))
|
||||
}.code == 0
|
||||
with("am force-stop $packageName") {
|
||||
listOf(
|
||||
toShizukuShellAction(),
|
||||
toRootShellAction(scriptRuntime),
|
||||
toFallbackShellAction(scriptRuntime),
|
||||
).first { it.condition() }.execute().code == 0
|
||||
}
|
||||
}
|
||||
|
||||
// @Hint by SuperMonster003 on Oct 30, 2024.
|
||||
@@ -792,7 +801,30 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
|
||||
fun killDual(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Boolean = ensureArgumentsLength(args, 1) { argList ->
|
||||
val packageName = getPackageName(scriptRuntime, argList) ?: return@ensureArgumentsLength false
|
||||
val command = "am force-stop $packageName"
|
||||
runCatching { execCommandForDualUser(scriptRuntime, command, RootUtils.isRootAvailable(), WrappedShizuku.isOperational()) }.isSuccess
|
||||
runCatching { execCommandForDualUser(scriptRuntime, command) }.isSuccess
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@RhinoRuntimeFunctionInterface
|
||||
fun isInstalled(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Boolean = ensureArgumentsOnlyOne(args) { o ->
|
||||
val packageName = getPackageName(scriptRuntime, arrayOf(o)) ?: return@ensureArgumentsOnlyOne false
|
||||
scriptRuntime.app.isInstalled(packageName)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@RhinoRuntimeFunctionInterface
|
||||
fun isDualInstalled(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Boolean = ensureArgumentsOnlyOne(args) { o ->
|
||||
val packageName = getPackageName(scriptRuntime, arrayOf(o)) ?: return@ensureArgumentsOnlyOne false
|
||||
isDualInstalledInternal(scriptRuntime, packageName)
|
||||
}
|
||||
|
||||
private fun isDualInstalledInternal(scriptRuntime: ScriptRuntime, packageName: String): Boolean {
|
||||
val command = "cmd package list packages %USER_ID% $packageName"
|
||||
return runCatching {
|
||||
execCommandForDualUser(scriptRuntime, command)?.let { result ->
|
||||
result.code == 0 && result.result.contains("package:$packageName")
|
||||
} ?: false
|
||||
}.getOrElse { false }
|
||||
}
|
||||
|
||||
private fun parseClassName(o: NativeObject): String {
|
||||
@@ -890,16 +922,16 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
|
||||
val intent = intentRhinoWithRuntime(scriptRuntime, o).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) }
|
||||
val command = "am start ${intentToShellRhino(intent)}"
|
||||
when (o) {
|
||||
is NativeObject -> {
|
||||
val withRoot = o.inquire("root", ::coerceBoolean, true)
|
||||
val withShizuku = o.inquire("shizuku", ::coerceBoolean, true)
|
||||
execCommandForDualUser(scriptRuntime, command, withRoot, withShizuku)
|
||||
}
|
||||
is NativeObject -> execCommandForDualUser(scriptRuntime, command, o)
|
||||
else -> execCommandForDualUser(scriptRuntime, command)
|
||||
}
|
||||
}
|
||||
|
||||
private fun execCommandForDualUser(scriptRuntime: ScriptRuntime, command: String, withRoot: Boolean = true, withShizuku: Boolean = true) {
|
||||
private fun execCommandForDualUser(
|
||||
scriptRuntime: ScriptRuntime,
|
||||
command: String,
|
||||
options: NativeObject? = null,
|
||||
): AbstractShell.Result? {
|
||||
val userManager = globalContext.getSystemService(Class.forName("android.os.UserManager"))
|
||||
|
||||
val getUserProfilesMethod = userManager.javaClass.getDeclaredMethod("getUserProfiles")
|
||||
@@ -911,19 +943,46 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
|
||||
|
||||
val userHandleClass = Class.forName("android.os.UserHandle")
|
||||
val getIdentifierMethod = userHandleClass.getDeclaredMethod("getIdentifier")
|
||||
val processUserIdentifier = getIdentifierMethod.invoke(processUserHandle) as Int
|
||||
val currentUserId = getIdentifierMethod.invoke(processUserHandle) as Int
|
||||
|
||||
var lastResult: AbstractShell.Result? = null
|
||||
|
||||
@Suppress("LocalVariableName")
|
||||
for (userHandle in userProfiles) {
|
||||
val currentUserIdentifier = getIdentifierMethod.invoke(userHandle) as Int
|
||||
if (currentUserIdentifier != processUserIdentifier) {
|
||||
val niceCommand = "$command --user $currentUserIdentifier"
|
||||
when {
|
||||
withRoot && RootUtils.isRootAvailable() -> Shell.execCommand(scriptRuntime, arrayOf<Any>(niceCommand, /* withRoot = */ true))
|
||||
withShizuku && WrappedShizuku.isOperational() -> WrappedShizuku.execCommand(niceCommand)
|
||||
else -> Shell.execCommand(scriptRuntime, arrayOf<Any>(niceCommand, /* withRoot = */ false))
|
||||
}.throwIfError()
|
||||
val uid = getIdentifierMethod.invoke(userHandle) as Int
|
||||
if (uid == currentUserId) continue
|
||||
|
||||
val cmd = when {
|
||||
command.contains("%USER_ID%") -> command.replace("%USER_ID%", "--user $uid")
|
||||
Regex("""\s--user\s+\d+""").containsMatchIn(command) -> command
|
||||
else -> "$command --user $uid"
|
||||
}
|
||||
|
||||
val shizuku = cmd.toShizukuShellAction()
|
||||
val root = cmd.toRootShellAction(scriptRuntime)
|
||||
val fallback = cmd.toFallbackShellAction(scriptRuntime)
|
||||
|
||||
val SRF = listOf(shizuku, root, fallback)
|
||||
val RSF = listOf(root, shizuku, fallback)
|
||||
|
||||
val actions = when (options) {
|
||||
is NativeObject -> {
|
||||
val preferShizuku = options.prop("shizuku").takeUnless { it.isJsNullish() }?.let { coerceBoolean(it) }
|
||||
val preferRoot = options.prop("root").takeUnless { it.isJsNullish() }?.let { coerceBoolean(it) }
|
||||
when (preferShizuku) {
|
||||
null -> if (preferRoot == true) RSF else SRF
|
||||
true -> SRF
|
||||
else -> if (preferRoot == false) SRF else RSF
|
||||
}
|
||||
}
|
||||
else -> SRF
|
||||
}
|
||||
|
||||
if (actions.first { it.condition() }.execute().also { lastResult = it }.code == 0) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return lastResult?.apply { throwIfError() }
|
||||
}
|
||||
|
||||
private fun getAppByAliasRhino(o: Any?): PresetApp? {
|
||||
@@ -953,11 +1012,11 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
|
||||
})
|
||||
}
|
||||
|
||||
private fun checkRootProperty(o: NativeObject) = o.inquire("root", ::coerceBoolean, false)
|
||||
private fun checkDualProperty(o: NativeObject) = o.inquire("dual", ::coerceBoolean, false)
|
||||
|
||||
private fun checkShizukuProperty(o: NativeObject) = o.inquire("shizuku", ::coerceBoolean, false) && WrappedShizuku.isOperational()
|
||||
|
||||
private fun checkDualProperty(o: NativeObject) = o.inquire("dual", ::coerceBoolean, false)
|
||||
private fun checkRootProperty(o: NativeObject) = o.inquire("root", ::coerceBoolean, false) && RootUtils.isRootAvailable()
|
||||
|
||||
private fun Intent.configure(scriptRuntime: ScriptRuntime, o: NativeObject): Intent {
|
||||
val intent = this
|
||||
@@ -1055,6 +1114,18 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
|
||||
return intent
|
||||
}
|
||||
|
||||
private data class ShellAction(val cmd: String, val condition: () -> Boolean, private val action: (cmd: String) -> AbstractShell.Result) {
|
||||
|
||||
fun execute() = action(cmd)
|
||||
|
||||
companion object {
|
||||
fun String.toShizukuShellAction() = ShellAction(this, { WrappedShizuku.isOperational() }, { WrappedShizuku.execCommand(it) })
|
||||
fun String.toRootShellAction(scriptRuntime: ScriptRuntime) = ShellAction(this, { RootUtils.isRootAvailable() }, { Shell.execCommand(scriptRuntime, arrayOf<Any>(it, /* withRoot = */ true)) })
|
||||
fun String.toFallbackShellAction(scriptRuntime: ScriptRuntime) = ShellAction(this, { true }, { Shell.execCommand(scriptRuntime, arrayOf<Any>(it, /* withRoot = */ false)) })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,26 +1,132 @@
|
||||
package org.autojs.autojs.util;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import com.stericson.RootShell.RootShell;
|
||||
import org.autojs.autojs.core.pref.Pref;
|
||||
import org.autojs.autojs6.R;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.autojs.autojs.util.StringUtils.getStringByLanguageTag;
|
||||
import static org.autojs.autojs.util.StringUtils.key;
|
||||
import static org.autojs.autojs.util.StringUtils.str;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.stericson.RootShell.RootShell;
|
||||
|
||||
import org.autojs.autojs.core.pref.Pref;
|
||||
import org.autojs.autojs6.R;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
|
||||
/**
|
||||
* Created by Stardust on Jan 26, 2018.
|
||||
* Modified by SuperMonster003 as of March 10, 2022.
|
||||
*/
|
||||
public class RootUtils {
|
||||
|
||||
private static final String[] COMMON_SU_PATHS = new String[]{
|
||||
"/system/xbin/su",
|
||||
"/system/bin/su",
|
||||
"/vendor/bin/su",
|
||||
"/system_ext/bin/su",
|
||||
"/odm/bin/su",
|
||||
"/sbin/su",
|
||||
"/su/bin/su",
|
||||
"/system/su"
|
||||
};
|
||||
private static String runtimeOverriddenRootMode = RootMode.AUTO_DETECT.key;
|
||||
|
||||
public static void setRootMode(RootMode mode, boolean isWriteInfoPreference) {
|
||||
if (isWriteInfoPreference) {
|
||||
Pref.setRootMode(mode);
|
||||
} else {
|
||||
runtimeOverriddenRootMode = mode.key;
|
||||
}
|
||||
}
|
||||
|
||||
public static void resetRuntimeOverriddenRootModeState() {
|
||||
runtimeOverriddenRootMode = RootMode.AUTO_DETECT.key;
|
||||
}
|
||||
|
||||
public static RootMode getRootMode() {
|
||||
if (runtimeOverriddenRootMode.equals(RootMode.AUTO_DETECT.key)) {
|
||||
return Pref.getRootMode();
|
||||
}
|
||||
return RootMode.getRootMode(runtimeOverriddenRootMode);
|
||||
}
|
||||
|
||||
public static void setRootMode(RootMode mode) {
|
||||
setRootMode(mode, false);
|
||||
}
|
||||
|
||||
public static boolean isRootAvailable() {
|
||||
RootMode rootMode = getRootMode();
|
||||
return rootMode == RootMode.AUTO_DETECT
|
||||
? isSuPresentFast() || getRootStateWithRootShell()
|
||||
: rootMode == RootMode.FORCE_ROOT;
|
||||
}
|
||||
|
||||
private static boolean isSuPresentFast() {
|
||||
try {
|
||||
// 1. Check common su paths.
|
||||
// zh-CN: 1. 检查常见 su 路径.
|
||||
for (String path : COMMON_SU_PATHS) {
|
||||
if (isExecutableFile(path)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Check su in PATH environment.
|
||||
// zh-CN: 2. 检查 PATH 环境中的 su.
|
||||
String envPath = System.getenv("PATH");
|
||||
if (envPath != null && !envPath.isEmpty()) {
|
||||
String[] paths = envPath.split(":");
|
||||
Set<String> uniq = new HashSet<>();
|
||||
for (String p : paths) {
|
||||
if (p == null || p.isEmpty()) continue;
|
||||
if (!uniq.add(p)) continue;
|
||||
String su = (p.endsWith("/") ? p : (p + "/")) + "su";
|
||||
if (isExecutableFile(su)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isExecutableFile(String absolutePath) {
|
||||
File f = new File(absolutePath);
|
||||
if (!(f.exists() && f.isFile())) return false;
|
||||
|
||||
// Quick check using File.canExecute().
|
||||
// zh-CN: 先用 File.canExecute() 快速判定.
|
||||
if (f.canExecute()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try an equivalent check using Os.access (using reflection to avoid class resolution issues).
|
||||
// zh-CN: 再尝试一次 Os.access 的等效判定 (使用反射避免类解析问题).
|
||||
try {
|
||||
Class<?> osClass = Class.forName("android.system.Os");
|
||||
Class<?> osConstantsClass = Class.forName("android.system.OsConstants");
|
||||
int xOk = osConstantsClass.getField("X_OK").getInt(null);
|
||||
osClass.getMethod("access", String.class, Integer.TYPE).invoke(null, absolutePath, xOk);
|
||||
return true;
|
||||
} catch (Throwable ignored) {
|
||||
// Reflection failed or class/method/field not found, consider as non-executable.
|
||||
// zh-CN: 反射失败或无此类/方法/字段, 视为不可执行.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean getRootStateWithRootShell() {
|
||||
try {
|
||||
return RootShell.isRootAvailable();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public enum RootMode {
|
||||
FORCE_ROOT(key(R.string.key_root_mode_force_root), getStringByLanguageTag(R.string.entry_root_mode_force_root, "en")),
|
||||
FORCE_NON_ROOT(key(R.string.key_root_mode_force_non_root), getStringByLanguageTag(R.string.entry_root_mode_force_non_root, "en")),
|
||||
@@ -50,43 +156,5 @@ public class RootUtils {
|
||||
|
||||
}
|
||||
|
||||
public static void setRootMode(RootMode mode) {
|
||||
setRootMode(mode, false);
|
||||
}
|
||||
|
||||
public static void setRootMode(RootMode mode, boolean isWriteInfoPreference) {
|
||||
if (isWriteInfoPreference) {
|
||||
Pref.setRootMode(mode);
|
||||
} else {
|
||||
runtimeOverriddenRootMode = mode.key;
|
||||
}
|
||||
}
|
||||
|
||||
public static void resetRuntimeOverriddenRootModeState() {
|
||||
runtimeOverriddenRootMode = RootMode.AUTO_DETECT.key;
|
||||
}
|
||||
|
||||
public static RootMode getRootMode() {
|
||||
if (runtimeOverriddenRootMode.equals(RootMode.AUTO_DETECT.key)) {
|
||||
return Pref.getRootMode();
|
||||
}
|
||||
return RootMode.getRootMode(runtimeOverriddenRootMode);
|
||||
}
|
||||
|
||||
public static boolean isRootAvailable() {
|
||||
RootMode rootMode = getRootMode();
|
||||
return rootMode == RootMode.AUTO_DETECT
|
||||
? getRootStateWithRootShell()
|
||||
: rootMode == RootMode.FORCE_ROOT;
|
||||
}
|
||||
|
||||
private static boolean getRootStateWithRootShell() {
|
||||
try {
|
||||
return RootShell.isRootAvailable();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -932,7 +932,7 @@
|
||||
<string name="text_result">نتيجة</string>
|
||||
<string name="text_revoke_autojs6_access_in_shizuku_app">قم بإلغاء الوصول إلى AutoJs6 في تطبيق Shizuku</string>
|
||||
<string name="text_rhino_java_primitive_wrap">تغليف الأنواع البدائية في Java</string>
|
||||
<string name="text_root_mode_title">فحص الجذر مجموعة القوة</string>
|
||||
<string name="text_root_mode_title">التحقق من صلاحيات الروت</string>
|
||||
<string name="text_run">يجري</string>
|
||||
<string name="text_run_on_battery_change">على البطارية تغيرت</string>
|
||||
<string name="text_run_on_boot">على التمهيد</string>
|
||||
|
||||
@@ -927,7 +927,7 @@
|
||||
<string name="text_result">Result</string>
|
||||
<string name="text_revoke_autojs6_access_in_shizuku_app">Revoke AutoJs6 access in Shizuku app</string>
|
||||
<string name="text_rhino_java_primitive_wrap">Java primitive wrapping</string>
|
||||
<string name="text_root_mode_title">Force set root check</string>
|
||||
<string name="text_root_mode_title">Root access check</string>
|
||||
<string name="text_run">Run</string>
|
||||
<string name="text_run_on_battery_change">On battery changed</string>
|
||||
<string name="text_run_on_boot">On booted</string>
|
||||
|
||||
@@ -930,7 +930,7 @@
|
||||
<string name="text_result">Resultado</string>
|
||||
<string name="text_revoke_autojs6_access_in_shizuku_app">Revocar privilegios de AutoJs6 en una aplicación Shizuku</string>
|
||||
<string name="text_rhino_java_primitive_wrap">Envoltorio de primitivos de Java</string>
|
||||
<string name="text_root_mode_title">Forzar la comprobación de root</string>
|
||||
<string name="text_root_mode_title">Comprobación de acceso root</string>
|
||||
<string name="text_run">Ejecutar</string>
|
||||
<string name="text_run_on_battery_change">Al cambiar la batería</string>
|
||||
<string name="text_run_on_boot">Al arrancar</string>
|
||||
|
||||
@@ -930,7 +930,7 @@
|
||||
<string name="text_result">Résultat</string>
|
||||
<string name="text_revoke_autojs6_access_in_shizuku_app">Révoquer les privilèges AutoJs6 dans une application Shizuku</string>
|
||||
<string name="text_rhino_java_primitive_wrap">Encapsulation des types primitifs Java</string>
|
||||
<string name="text_root_mode_title">Force set root check</string>
|
||||
<string name="text_root_mode_title">Vérification de l\'accès root</string>
|
||||
<string name="text_run">Exécuter</string>
|
||||
<string name="text_run_on_battery_change">Sur changement de batterie</string>
|
||||
<string name="text_run_on_boot">Sur démarrage</string>
|
||||
|
||||
@@ -931,7 +931,7 @@
|
||||
<string name="text_result">結果</string>
|
||||
<string name="text_revoke_autojs6_access_in_shizuku_app">Shizuku アプリケーションで AutoJs6 権限を取り消す</string>
|
||||
<string name="text_rhino_java_primitive_wrap">Java プリミティブ型のラップ</string>
|
||||
<string name="text_root_mode_title">強制的に root にするチェック</string>
|
||||
<string name="text_root_mode_title">Root 権限の確認</string>
|
||||
<string name="text_run">実行</string>
|
||||
<string name="text_run_on_battery_change">バッテリー交換時</string>
|
||||
<string name="text_run_on_boot">起動したとき</string>
|
||||
|
||||
@@ -932,7 +932,7 @@
|
||||
<string name="text_result">결과</string>
|
||||
<string name="text_revoke_autojs6_access_in_shizuku_app">Shizuku 애플리케이션에서 AutoJs6 권한 취소하기</string>
|
||||
<string name="text_rhino_java_primitive_wrap">Java 원시 타입 래핑</string>
|
||||
<string name="text_root_mode_title">강제 설정 루트 검사</string>
|
||||
<string name="text_root_mode_title">루트 권한 확인</string>
|
||||
<string name="text_run">운영</string>
|
||||
<string name="text_run_on_battery_change">배터리가 변경되었습니다</string>
|
||||
<string name="text_run_on_boot">부팅</string>
|
||||
|
||||
@@ -930,7 +930,7 @@
|
||||
<string name="text_result">Результат</string>
|
||||
<string name="text_revoke_autojs6_access_in_shizuku_app">Отмена привилегий AutoJs6 в приложении Shizuku</string>
|
||||
<string name="text_rhino_java_primitive_wrap">Обёртка примитивов Java</string>
|
||||
<string name="text_root_mode_title">Проверка принудительной установки root</string>
|
||||
<string name="text_root_mode_title">Проверка прав root</string>
|
||||
<string name="text_run">Запустить</string>
|
||||
<string name="text_run_on_battery_change">При смене батареи</string>
|
||||
<string name="text_run_on_boot">При загрузке</string>
|
||||
|
||||
@@ -928,7 +928,7 @@
|
||||
<string name="text_result">結果</string>
|
||||
<string name="text_revoke_autojs6_access_in_shizuku_app">在 Shizuku 應用中撤銷 AutoJs6 權限</string>
|
||||
<string name="text_rhino_java_primitive_wrap">Java 原始類型包裝</string>
|
||||
<string name="text_root_mode_title">強制 Root 權限檢查</string>
|
||||
<string name="text_root_mode_title">Root 權限檢查</string>
|
||||
<string name="text_run">運行</string>
|
||||
<string name="text_run_on_battery_change">電量變化時</string>
|
||||
<string name="text_run_on_boot">開機時</string>
|
||||
|
||||
@@ -928,7 +928,7 @@
|
||||
<string name="text_result">結果</string>
|
||||
<string name="text_revoke_autojs6_access_in_shizuku_app">在 Shizuku 應用中撤銷 AutoJs6 許可權</string>
|
||||
<string name="text_rhino_java_primitive_wrap">Java 原始型別包裝</string>
|
||||
<string name="text_root_mode_title">強制 Root 許可權檢查</string>
|
||||
<string name="text_root_mode_title">Root 許可權檢查</string>
|
||||
<string name="text_run">執行</string>
|
||||
<string name="text_run_on_battery_change">電量變化時</string>
|
||||
<string name="text_run_on_boot">開機時</string>
|
||||
|
||||
@@ -928,7 +928,7 @@
|
||||
<string name="text_result">结果</string>
|
||||
<string name="text_revoke_autojs6_access_in_shizuku_app">在 Shizuku 应用中撤销 AutoJs6 权限</string>
|
||||
<string name="text_rhino_java_primitive_wrap">Java 原始类型包装</string>
|
||||
<string name="text_root_mode_title">强制 Root 权限检查</string>
|
||||
<string name="text_root_mode_title">Root 权限检查</string>
|
||||
<string name="text_run">运行</string>
|
||||
<string name="text_run_on_battery_change">电量变化时</string>
|
||||
<string name="text_run_on_boot">开机时</string>
|
||||
|
||||
@@ -1181,7 +1181,7 @@
|
||||
<string name="text_result">Result</string>
|
||||
<string name="text_revoke_autojs6_access_in_shizuku_app">Revoke AutoJs6 access in Shizuku app</string>
|
||||
<string name="text_rhino_java_primitive_wrap">Java primitive wrapping</string>
|
||||
<string name="text_root_mode_title">Force set root check</string>
|
||||
<string name="text_root_mode_title">Root access check</string>
|
||||
<string name="text_run">Run</string>
|
||||
<string name="text_run_on_battery_change">On battery changed</string>
|
||||
<string name="text_run_on_boot">On booted</string>
|
||||
|
||||
Reference in New Issue
Block a user