6.0.3 - 新增使用修改安全设置权限自启无障碍 修复toast/socket导致崩溃 资源英文补全 支持64位系统 部分插件及工具版本更新

This commit is contained in:
SuperMonster003
2022-03-20 00:10:02 +08:00
parent ec61eb5000
commit a8ce1b9acb
185 changed files with 4018 additions and 3877 deletions

View File

@@ -46,10 +46,10 @@ dependencies {
implementation 'net.lingala.zip4j:zip4j:2.9.1'
// OkHttp
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.4'
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.6'
// Gson
implementation 'com.google.code.gson:gson:2.8.9'
implementation 'com.google.code.gson:gson:2.9.0'
// Log4j
implementation 'de.mindpipe.android:android-logging-log4j:1.0.3'

View File

@@ -18,7 +18,7 @@
<application>
<activity
android:name=".execution.ScriptExecuteActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:configChanges="keyboardHidden|orientation|screenSize|locale"
android:theme="@style/ScriptTheme" />

View File

@@ -63,7 +63,7 @@ runtime.init();
(function (scope) {
var modules = ['app', 'automator', 'console', 'dialogs', 'io', 'selector', 'shell', 'web', 'ui',
'images', 'threads', 'events', 'engines', 'RootAutomator', 'http', 'storages', 'floaty',
'sensors', 'media', 'plugins', 'continuation', '$base64'];
'sensors', 'media', 'plugins', 'continuation', '$base64', 'recorder'];
var len = modules.length;
for (var i = 0; i < len; i++) {
var m = modules[i];

View File

@@ -84,7 +84,7 @@ module.exports = function (runtime, global) {
de: Packages.de,
okhttp3: Packages.okhttp3,
androidx: Packages.androidx,
toast(msg, is_long, is_forcible) {
toast(msg, isLong, isForcible) {
let $ = {
toast() {
this.init(arguments);
@@ -92,18 +92,18 @@ module.exports = function (runtime, global) {
},
init() {
this.message = isNullish(msg) ? '' : msg.toString();
this.is_long = this.parseIsLong(is_long);
this.is_forcible = is_forcible;
this.isLong = this.parseIsLong(isLong);
this.isForcible = isForcible;
},
parseIsLong(is_long) {
if (typeof is_long === 'number') {
return Number(!!is_long);
parseIsLong(isLong) {
if (typeof isLong === 'number') {
return Number(!!isLong);
}
if (typeof is_long === 'string') {
return Number(/^l(ong)?$/i.test(is_long));
if (typeof isLong === 'string') {
return Number(/^l(ong)?$/i.test(isLong));
}
if (typeof is_long === 'boolean') {
return Number(is_long);
if (typeof isLong === 'boolean') {
return Number(isLong);
}
return 0;
},
@@ -111,12 +111,12 @@ module.exports = function (runtime, global) {
ui.post(() => {
new android.os.Handler(Looper.getMainLooper()).post(new Runnable({
run() {
if ($.is_forcible) {
$.dismiss();
if (isForcible) {
_.toasts.dismiss();
}
$.toastObj = Toast.makeText(context, $.message, $.is_long);
_.toasts.add($.toastObj);
$.toastObj.show();
let o = Toast.makeText(context, $.message, $.isLong);
_.toasts.add(o);
o.show();
},
}));
});
@@ -125,7 +125,7 @@ module.exports = function (runtime, global) {
$.toast();
},
toastLog(msg, is_long, is_forcible) {
toastLog(msg, isLong, isForcible) {
this.toast.apply(this, arguments);
this.log(msg);
},

View File

@@ -1,3 +1,3 @@
module.exports = function(runtime, global){
module.exports = function (runtime, global) {
return Object.create(runtime.media);
}
};

View File

@@ -1,12 +1,11 @@
module.exports = function (runtime, scope) {
function plugins(){
}
const plugins = () => void 0;
plugins.load = function(packageName){
var plugin = runtime.plugins.load(packageName);
var index = require(plugin.mainScriptPath);
plugins.load = function (packageName) {
let plugin = runtime.plugins.load(packageName);
let index = require(plugin.getMainScriptPath());
return index(plugin.unwrap());
}
};
return plugins;
}
};

View File

@@ -0,0 +1,127 @@
module.exports = function () {
let _ = {
/**
* @type {Object.<string,number>}
*/
keys: {},
/**
* @type {number[]}
*/
anonymity: [],
/**
* @param {?number} [ts]
* @return {number}
*/
ts(ts) {
return typeof ts === 'number' ? ts : Date.now();
},
/**
* @param {string} [key]
* @return {boolean}
*/
has(key) {
return key in this.keys;
},
clear() {
this.keys = {};
this.anonymity.splice(0);
},
/**
* @param {string} [key]
* @param {?number} [ts]
* @return {number}
*/
add(key, ts) {
key === undefined
? this.anonymity.push(this.ts(ts))
: this.keys[key] = this.ts(ts);
return this.ts(ts);
},
/**
* @param {string} [key]
* @param {boolean} [isErrorSuppressed=false]
* @return {number|void}
*/
get(key, isErrorSuppressed) {
if (key === undefined) {
return this.anonymity.pop();
}
if (!this.has(key) && !isErrorSuppressed) {
throw Error(`key "${key}" does not exist`);
}
return this.keys[key];
},
/**
* @param {string} [key]
* @param {?number} [ts]
* @return {number}
*/
save(key, ts) {
return this.add(key, ts);
},
/**
* @param {string} [key]
* @param {?number} [ts]
* @return {number}
*/
load(key, ts) {
return this.ts(ts) - this.get(key);
},
/**
* @param {string} key
* @returns {boolean}
*/
remove(key) {
return delete this.keys[key];
},
/**
* @param {string|function} [key]
* @param {?number|ThisType<any>} [ts]
* @return {number}
*/
shortcut(key, ts) {
if (typeof key === 'function') {
let k = `${key.name || 'anonymous'}@${Date.now()}`;
this.save(k);
key.call(typeof ts === 'object' ? ts : null);
let res = this.load(k);
this.remove(k);
return res;
}
return typeof key !== 'undefined'
? this.has(key) ? this.load(key, ts) : this.save(key, ts)
: this.anonymity.length ? this.load() : this.save();
},
};
/**
* Record or get the record for a time gap
* @param {string|function} [key]
* @param {number|ThisType<any>} [ts]
* @return {number|void} - timestamp
*/
const recorder = function (key, ts) {
return _.shortcut(key, ts);
};
/**
* @param {string} [key]
* @param {number} [ts=Date.now()]
*/
recorder.save = (key, ts) => _.save(key, ts);
/**
* @param {string} [key]
* @param {number} [ts=Date.now()]
* @return {number}
*/
recorder.load = (key, ts) => _.load(key, ts);
recorder.isLessThan = (key, compare) => _.load(key) < compare;
recorder.isGreaterThan = (key, compare) => _.load(key) > compare;
recorder.has = key => _.has(key);
recorder.remove = key => _.remove(key);
recorder.clear = () => _.clear();
return recorder;
};

View File

@@ -1,4 +1,3 @@
module.exports = function(runtime, global){
var sensors = Object.create(runtime.sensors);
return sensors;
module.exports = function (runtime, global) {
return Object.create(runtime.sensors);
};

View File

@@ -13,8 +13,10 @@ import androidx.annotation.RequiresApi;
import com.stardust.app.OnActivityResultDelegate;
import com.stardust.app.SimpleActivityLifecycleCallbacks;
import com.stardust.autojs.core.accessibility.AccessibilityBridge;
import com.stardust.autojs.core.console.GlobalConsole;
import com.stardust.autojs.core.accessibility.SimpleActionAutomator;
import com.stardust.autojs.core.activity.ActivityInfoProvider;
import com.stardust.autojs.core.console.ConsoleImpl;
import com.stardust.autojs.core.console.GlobalConsole;
import com.stardust.autojs.core.image.capture.ScreenCaptureRequestActivity;
import com.stardust.autojs.core.image.capture.ScreenCaptureRequester;
import com.stardust.autojs.core.record.accessibility.AccessibilityActionRecorder;
@@ -31,7 +33,6 @@ import com.stardust.autojs.script.JavaScriptSource;
import com.stardust.util.ResourceMonitor;
import com.stardust.util.ScreenMetrics;
import com.stardust.util.UiHandler;
import com.stardust.autojs.core.activity.ActivityInfoProvider;
import com.stardust.view.accessibility.AccessibilityNotificationObserver;
import com.stardust.view.accessibility.AccessibilityService;
import com.stardust.view.accessibility.LayoutInspector;
@@ -59,6 +60,7 @@ public abstract class AutoJs {
private final ScreenCaptureRequester mScreenCaptureRequester = new ScreenCaptureRequesterImpl();
private final ScriptEngineService mScriptEngineService;
private final GlobalConsole mGlobalConsole;
private ScriptRuntime mGlobalRuntime;
protected AutoJs(final Application application) {
@@ -96,7 +98,7 @@ public abstract class AutoJs {
exception.fillInStackTrace();
return exception;
});
ResourceMonitor.setUnclosedResourceDetectedHandler(detectedException -> mGlobalConsole.error(detectedException));
ResourceMonitor.setUnclosedResourceDetectedHandler(mGlobalConsole::error);
}
public abstract void ensureAccessibilityServiceEnabled();
@@ -122,13 +124,24 @@ public abstract class AutoJs {
mScriptEngineManager = new ScriptEngineManager(mContext);
mScriptEngineManager.registerEngine(JavaScriptSource.ENGINE, () -> {
LoopBasedJavaScriptEngine engine = new LoopBasedJavaScriptEngine(mContext);
engine.setRuntime(createRuntime());
mGlobalRuntime = createRuntime();
engine.setRuntime(mGlobalRuntime);
return engine;
});
initContextFactory();
mScriptEngineManager.registerEngine(AutoFileSource.ENGINE, () -> new RootAutomatorEngine(mContext));
}
@NonNull
public ScriptRuntime getGlobalRuntime() {
return mGlobalRuntime;
}
@NonNull
public SimpleActionAutomator getGlobalAutomator() {
return mGlobalRuntime.automator;
}
protected void initContextFactory() {
ContextFactory.initGlobal(new InterruptibleAndroidContextFactory(new File(mContext.getCacheDir(), "classes")));
}

View File

@@ -0,0 +1,219 @@
package com.stardust.autojs.core.accessibility
import android.content.ActivityNotFoundException
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.provider.Settings
import android.provider.Settings.Secure
import android.text.TextUtils
import android.util.Log
import android.widget.Toast
import com.stardust.app.GlobalAppContext
import com.stardust.autojs.R
import com.stardust.autojs.core.pref.Pref
import com.stardust.autojs.core.util.ProcessShell
import com.stardust.view.accessibility.AccessibilityService.Companion
import org.autojs.autojs.tool.RootTool
import org.autojs.autojs.tool.SettingsTool
import java.util.*
/**
* Created by Stardust on 2017/1/26.
* Modified by SuperMonster003 as of Feb 15, 2022.
*/
class AccessibilityServiceTool(val context: Context) {
val tag: String = AccessibilityServiceTool::class.java.simpleName
fun goToAccessibilitySetting() {
if (Pref.isFirstGoToAccessibilitySetting()) {
GlobalAppContext.toast(getString(R.string.text_please_choose) + " " + getString(R.string.app_name), Toast.LENGTH_LONG)
}
try {
context.startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
} catch (e: ActivityNotFoundException) {
GlobalAppContext.toast(getString(R.string.go_to_accessibility_settings), Toast.LENGTH_LONG)
}
}
private fun getString(resId: Int): String {
val context = GlobalAppContext.get()
return context.getString(resId)
}
private fun getComponentName(): ComponentName {
return ComponentName(context, getAccessibilityServiceJavaClass())
}
fun enableAccessibilityService(): Boolean {
return when {
enableAccessibilityServiceAutomaticallyIfNeeded() -> true
else -> {
goToAccessibilitySetting()
false
}
}
}
private fun enableAccessibilityServiceByRootIfNeeded(): Boolean =
Pref.shouldEnableAccessibilityServiceByRoot()
&& RootTool.isRootAvailable()
&& enableAccessibilityServiceByRoot()
private fun enableAccessibilityServiceByRootIfNeededAndWaitFor(timeout: Int): Boolean =
Pref.shouldEnableAccessibilityServiceByRoot()
&& RootTool.isRootAvailable()
&& enableAccessibilityServiceByRootAndWaitFor(timeout)
private fun enableAccessibilityServiceBySecureSettingsIfNeeded(): Boolean =
Pref.shouldEnableAccessibilityServiceBySecureSettings()
&& SettingsTool.SecureSettings.isGranted(context)
&& enableAccessibilityServiceBySecureSettings()
private fun enableAccessibilityServiceBySecureSettingsIfNeededAndWaitFor(timeout: Int): Boolean =
Pref.shouldEnableAccessibilityServiceBySecureSettings()
&& SettingsTool.SecureSettings.isGranted(context)
&& enableAccessibilityServiceBySecureSettingsAndWaitFor(timeout)
fun disableAccessibilityService(): Boolean {
Companion.instance?.disableSelf()
when {
!isAccessibilityServiceEnabled() -> {
Log.d(tag, "disableAccessibilityService: " + "disableSelf succeeded")
return true
}
Pref.shouldEnableAccessibilityServiceBySecureSettings() && SettingsTool.SecureSettings.isGranted(context) -> when {
disableAccessibilityServiceBySecureSettings() -> return true
}
}
goToAccessibilitySetting()
return false
}
fun isAccessibilityServiceEnabled(): Boolean {
val expectedComponentName = getComponentName()
val enabledServicesSetting = Secure.getString(context.contentResolver, Secure.ENABLED_ACCESSIBILITY_SERVICES)
?: return false
val colonSplitter = TextUtils.SimpleStringSplitter(':')
colonSplitter.setString(enabledServicesSetting)
while (colonSplitter.hasNext()) {
val componentNameString = colonSplitter.next()
val enabledService = ComponentName.unflattenFromString(componentNameString)
if (enabledService != null && enabledService == expectedComponentName)
return true
}
return false
}
private fun enableAccessibilityServiceByRootAndWaitFor(timeout: Int): Boolean {
return when {
enableAccessibilityServiceByRoot() -> {
Companion.waitForEnabled(timeout.toLong())
}
else -> false
}
}
private fun enableAccessibilityServiceBySecureSettingsAndWaitFor(timeout: Int): Boolean {
return when {
enableAccessibilityServiceBySecureSettings() -> {
Companion.waitForEnabled(timeout.toLong())
}
else -> false
}
}
private fun enableAccessibilityServiceByRoot(): Boolean {
val cmd = """
enabled=$(settings get secure enabled_accessibility_services)
pkg=%s
if [[ ${"$"}enabled != *${"$"}pkg* ]]
then
enabled=${"$"}pkg:${"$"}enabled
settings put secure enabled_accessibility_services ${"$"}enabled
fi
settings put secure accessibility_enabled 1
"""
val serviceName = getServiceName()
return try {
TextUtils.isEmpty(ProcessShell.execCommand(String.format(Locale.getDefault(), cmd, serviceName), true).error)
} catch (e: Exception) {
false
}
}
private fun getServiceName(): String {
return context.packageName + "/" + getAccessibilityServiceJavaClass().name
}
private fun enableAccessibilityServiceBySecureSettings(): Boolean {
return try {
Secure.putString(context.contentResolver, Secure.ENABLED_ACCESSIBILITY_SERVICES, getEnabledServicesWithAutoJs())
Secure.putInt(context.contentResolver, Secure.ACCESSIBILITY_ENABLED, 1)
return isAccessibilityServiceEnabled()
} catch (e: Exception) {
false
}
}
private fun disableAccessibilityServiceBySecureSettings(): Boolean {
return try {
Secure.putString(context.contentResolver, Secure.ENABLED_ACCESSIBILITY_SERVICES, getEnabledServicesWithoutAutoJs())
Secure.putInt(context.contentResolver, Secure.ACCESSIBILITY_ENABLED, 0)
return !isAccessibilityServiceEnabled()
} catch (e: Exception) {
false
}
}
private fun getEnabledServices(): String {
return Secure.getString(context.contentResolver, Secure.ENABLED_ACCESSIBILITY_SERVICES) ?: ""
}
private fun getEnabledServicesWithAutoJs(): String {
var enabled: String = getEnabledServices()
val enabledList: List<String> = enabled.split(":")
if (enabledList.indexOf(getServiceName()) == -1) {
enabled = enabledList.joinToString(":") + ":" + getServiceName()
}
return enabled
}
private fun getEnabledServicesWithoutAutoJs(): String {
var enabled: String = getEnabledServices()
val enabledList: List<String> = enabled.split(":")
val serverName = getServiceName()
if (enabledList.indexOf(serverName) > 0) {
enabled = enabledList.filter { s: String -> s != serverName }.joinToString(":")
}
return enabled
}
private fun getAccessibilityServiceJavaClass(): Class<AccessibilityService> {
return AccessibilityService::class.java
}
fun enableAccessibilityServiceAutomaticallyIfNeeded(): Boolean {
return when {
enableAccessibilityServiceByRootIfNeeded() -> true
enableAccessibilityServiceBySecureSettingsIfNeeded() -> true
else -> false
}
}
fun enableAccessibilityServiceAutomaticallyIfNeededAndWaitFor(timeout: Int): Boolean {
return when {
enableAccessibilityServiceByRootIfNeededAndWaitFor(timeout) -> true
enableAccessibilityServiceBySecureSettingsIfNeededAndWaitFor(timeout) -> true
else -> false
}
}
}

View File

@@ -2,6 +2,8 @@ package com.stardust.autojs.core.console;
import android.content.Context;
import android.content.res.TypedArray;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -25,6 +27,7 @@ import com.stardust.util.SparseArrayEntries;
import java.util.ArrayList;
import java.util.Map;
import java.util.Objects;
/**
* Created by Stardust on 2017/5/2.
@@ -57,9 +60,8 @@ public class ConsoleView extends FrameLayout implements ConsoleImpl.LogListener
private RecyclerView mLogListRecyclerView;
private EditText mEditText;
private ResizableExpandableFloatyWindow mWindow;
private LinearLayout mInputContainer;
private boolean mShouldStopRefresh = false;
private ArrayList<ConsoleImpl.LogEntry> mLogEntries = new ArrayList<>();
private final ArrayList<ConsoleImpl.LogEntry> mLogEntries = new ArrayList<>();
public ConsoleView(Context context) {
super(context);
@@ -89,6 +91,7 @@ public class ConsoleView extends FrameLayout implements ConsoleImpl.LogListener
int logLevel = attr.getValue();
mColors.put(logLevel, typedArray.getColor(styleable, mColors.get(logLevel)));
}
typedArray.recycle();
}
mLogListRecyclerView = findViewById(R.id.log_list);
LinearLayoutManager manager = new LinearLayoutManager(getContext());
@@ -118,7 +121,7 @@ public class ConsoleView extends FrameLayout implements ConsoleImpl.LogListener
private void initEditText() {
mEditText = findViewById(R.id.input);
mEditText.setFocusableInTouchMode(true);
mInputContainer = findViewById(R.id.input_container);
LinearLayout mInputContainer = findViewById(R.id.input_container);
OnClickListener listener = v -> {
if (mWindow != null) {
mWindow.requestWindowFocus();
@@ -165,7 +168,7 @@ public class ConsoleView extends FrameLayout implements ConsoleImpl.LogListener
public void onLogClear() {
post(() -> {
mLogEntries.clear();
mLogListRecyclerView.getAdapter().notifyDataSetChanged();
Objects.requireNonNull(mLogListRecyclerView.getAdapter()).notifyDataSetChanged();
});
}
@@ -189,7 +192,7 @@ public class ConsoleView extends FrameLayout implements ConsoleImpl.LogListener
mLogEntries.add(logEntries.get(i));
}
}
mLogListRecyclerView.getAdapter().notifyItemRangeInserted(oldSize, size - 1);
Objects.requireNonNull(mLogListRecyclerView.getAdapter()).notifyItemRangeInserted(oldSize, size - 1);
mLogListRecyclerView.scrollToPosition(size - 1);
}
}
@@ -206,7 +209,7 @@ public class ConsoleView extends FrameLayout implements ConsoleImpl.LogListener
});
}
private class ViewHolder extends RecyclerView.ViewHolder {
private static class ViewHolder extends RecyclerView.ViewHolder {
TextView textView;
@@ -218,8 +221,9 @@ public class ConsoleView extends FrameLayout implements ConsoleImpl.LogListener
private class Adapter extends RecyclerView.Adapter<ViewHolder> {
@NonNull
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.console_view_item, parent, false));
}

View File

@@ -1,8 +1,9 @@
package com.stardust.autojs.core.opencv;
import androidx.annotation.NonNull;
import com.stardust.util.ResourceMonitor;
import org.mozilla.javascript.ScriptRuntime;
import org.opencv.core.Range;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
@@ -73,6 +74,7 @@ public class Mat extends org.opencv.core.Mat implements ResourceMonitor.Resource
ResourceMonitor.onOpen(this);
}
@NonNull
@Override
public Mat clone() {
return new Mat(n_clone(this.nativeObj));
@@ -80,7 +82,11 @@ public class Mat extends org.opencv.core.Mat implements ResourceMonitor.Resource
protected long n_clone(long addr) {
try {
return (long) nClone.invoke(this, addr);
Object cloned = nClone.invoke(this, addr);
if (cloned != null) {
return (long) cloned;
}
throw new Exception("Cloned is null");
} catch (Exception e) {
throw new RuntimeException(e);
}

View File

@@ -1,11 +1,16 @@
package com.stardust.autojs.core.pref
import android.content.Context
import android.content.SharedPreferences
import androidx.preference.PreferenceManager
import com.stardust.app.GlobalAppContext
import com.stardust.autojs.R
object Pref {
private val preferences = PreferenceManager.getDefaultSharedPreferences(GlobalAppContext.get())
private val DISPOSABLE_BOOLEAN = GlobalAppContext.get().getSharedPreferences("DISPOSABLE_BOOLEAN", Context.MODE_PRIVATE)
val isStableModeEnabled: Boolean
get() {
return preferences.getBoolean("key_stable_mode", false)
@@ -15,4 +20,33 @@ object Pref {
get() {
return preferences.getBoolean("key_gesture_observing", false)
}
}
fun isFirstGoToAccessibilitySetting(): Boolean {
return getDisposableBoolean("isFirstGoToAccessibilitySetting", false)
}
@Suppress("SameParameterValue")
private fun getDisposableBoolean(key: String, defaultValue: Boolean): Boolean {
val b: Boolean = DISPOSABLE_BOOLEAN.getBoolean(key, defaultValue)
if (b == defaultValue) {
DISPOSABLE_BOOLEAN.edit().putBoolean(key, !defaultValue).apply()
}
return b
}
fun shouldEnableAccessibilityServiceByRoot(): Boolean {
return def().getBoolean(getString(R.string.key_enable_a11y_service_with_root_access), true)
}
fun shouldEnableAccessibilityServiceBySecureSettings(): Boolean {
return def().getBoolean(getString(R.string.key_enable_a11y_service_with_secure_settings), true)
}
private fun def(): SharedPreferences {
return PreferenceManager.getDefaultSharedPreferences(GlobalAppContext.get())
}
private fun getString(id: Int): String {
return GlobalAppContext.getString(id)
}
}

View File

@@ -1,13 +1,20 @@
package com.stardust.autojs.core.ui.attribute;
import static com.stardust.autojs.core.ui.inflater.inflaters.BaseViewInflater.DRAWABLE_CACHE_QUALITIES;
import static com.stardust.autojs.core.ui.inflater.inflaters.BaseViewInflater.IMPORTANT_FOR_ACCESSIBILITY;
import static com.stardust.autojs.core.ui.inflater.inflaters.BaseViewInflater.LAYOUT_DIRECTIONS;
import static com.stardust.autojs.core.ui.inflater.inflaters.BaseViewInflater.SCROLLBARS_STYLES;
import static com.stardust.autojs.core.ui.inflater.inflaters.BaseViewInflater.SCROLL_INDICATORS;
import static com.stardust.autojs.core.ui.inflater.inflaters.BaseViewInflater.TEXT_ALIGNMENTS;
import static com.stardust.autojs.core.ui.inflater.inflaters.BaseViewInflater.TEXT_DIRECTIONS;
import static com.stardust.autojs.core.ui.inflater.inflaters.BaseViewInflater.TINT_MODES;
import static com.stardust.autojs.core.ui.inflater.inflaters.BaseViewInflater.VISIBILITY;
import android.annotation.SuppressLint;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Build;
import androidx.annotation.CallSuper;
import androidx.core.view.ViewCompat;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
@@ -15,6 +22,9 @@ import android.widget.CompoundButton;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import androidx.annotation.CallSuper;
import androidx.core.view.ViewCompat;
import com.stardust.autojs.core.internal.Functions;
import com.stardust.autojs.core.ui.inflater.ResourceParser;
import com.stardust.autojs.core.ui.inflater.util.Dimensions;
@@ -29,16 +39,6 @@ import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import static com.stardust.autojs.core.ui.inflater.inflaters.BaseViewInflater.DRAWABLE_CACHE_QUALITIES;
import static com.stardust.autojs.core.ui.inflater.inflaters.BaseViewInflater.IMPORTANT_FOR_ACCESSIBILITY;
import static com.stardust.autojs.core.ui.inflater.inflaters.BaseViewInflater.LAYOUT_DIRECTIONS;
import static com.stardust.autojs.core.ui.inflater.inflaters.BaseViewInflater.SCROLLBARS_STYLES;
import static com.stardust.autojs.core.ui.inflater.inflaters.BaseViewInflater.SCROLL_INDICATORS;
import static com.stardust.autojs.core.ui.inflater.inflaters.BaseViewInflater.TEXT_ALIGNMENTS;
import static com.stardust.autojs.core.ui.inflater.inflaters.BaseViewInflater.TEXT_DIRECTIONS;
import static com.stardust.autojs.core.ui.inflater.inflaters.BaseViewInflater.TINT_MODES;
import static com.stardust.autojs.core.ui.inflater.inflaters.BaseViewInflater.VISIBILITY;
public class ViewAttributes {
public interface Getter<T> {
@@ -55,8 +55,7 @@ public class ViewAttributes {
void set(String value);
}
protected class BaseAttribute implements Attribute {
protected static class BaseAttribute implements Attribute {
private String mValue;
private final AttributeSetter mAttributeSetter;
@@ -80,7 +79,6 @@ public class ViewAttributes {
protected interface AttributeGetter extends Getter<String> {
}
protected interface AttributeSetter extends Setter<String> {
}
@@ -104,8 +102,7 @@ public class ViewAttributes {
}
}
private Map<String, Attribute> mAttributes = new HashMap<>();
private final Map<String, Attribute> mAttributes = new HashMap<>();
private final Drawables mDrawables;
private final View mView;
private ViewAttributeDelegate mViewAttributeDelegate;
@@ -170,7 +167,6 @@ public class ViewAttributes {
onRegisterAttrs();
}
@CallSuper
protected void onRegisterAttrs() {
registerAttr("id", Ids::parse, mView::setId);
@@ -251,27 +247,19 @@ public class ViewAttributes {
}
protected void setForegroundTintMode(PorterDuff.Mode mode) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mView.setForegroundTintMode(mode);
}
mView.setForegroundTintMode(mode);
}
protected void setForegroundGravity(int g) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mView.setForegroundGravity(g);
}
mView.setForegroundGravity(g);
}
protected void setForeground(Drawable foreground) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mView.setForeground(foreground);
}
mView.setForeground(foreground);
}
protected void forceHasOverlappingRendering(boolean b) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mView.forceHasOverlappingRendering(b);
}
mView.forceHasOverlappingRendering(b);
}
protected void setElevation(int e) {
@@ -288,7 +276,6 @@ public class ViewAttributes {
}
}
protected float parseDimensionToPixel(String value) {
return Dimensions.parseToPixel(mView, value);
}
@@ -297,17 +284,12 @@ public class ViewAttributes {
return Dimensions.parseToIntPixel(value, mView);
}
protected int parseDimension(String dim) {
switch (dim) {
case "wrap_content":
return ViewGroup.LayoutParams.WRAP_CONTENT;
case "fill_parent":
case "match_parent":
return ViewGroup.LayoutParams.MATCH_PARENT;
default:
return Dimensions.parseToPixel(dim, mView, (ViewGroup) mView.getParent(), true);
}
return switch (dim) {
case "wrap_content" -> ViewGroup.LayoutParams.WRAP_CONTENT;
case "fill_parent", "match_parent" -> ViewGroup.LayoutParams.MATCH_PARENT;
default -> Dimensions.parseToPixel(dim, mView, (ViewGroup) mView.getParent(), true);
};
}
protected void registerAttr(String name, Attribute attribute) {
@@ -355,11 +337,11 @@ public class ViewAttributes {
registerAttrs(names, new MappingAttributeSetter<>(converter, applier));
}
protected <T> void registerAttrs(String[] names, AttributeSetter setter) {
protected void registerAttrs(String[] names, AttributeSetter setter) {
registerAttrs(names, new BaseAttribute(setter));
}
protected <T> void registerAttrs(String[] names, Attribute attribute) {
protected void registerAttrs(String[] names, Attribute attribute) {
for (String name : names) {
mAttributes.put(name, attribute);
}
@@ -370,7 +352,6 @@ public class ViewAttributes {
this::parseDrawable, applier)));
}
protected void registerDrawableAttrs(String[] names, Setter<Drawable> applier) {
registerAttrs(names, new BaseAttribute(new MappingAttributeSetter<>(
this::parseDrawable, applier)));
@@ -392,7 +373,6 @@ public class ViewAttributes {
registerAttr(name, Boolean::parseBoolean, applier);
}
protected Drawable parseDrawable(String value) {
return mDrawables.parse(mView, value);
}
@@ -409,42 +389,35 @@ public class ViewAttributes {
}
protected void setMargin(String margin) {
if (mView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mView.getLayoutParams();
if (mView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams params) {
int[] pixels = Dimensions.parseToIntPixelArray(getView(), margin);
params.setMargins(pixels[0], pixels[1], pixels[2], pixels[3]);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
params.setMarginStart(pixels[0]);
params.setMarginEnd(pixels[2]);
}
params.setMarginStart(pixels[0]);
params.setMarginEnd(pixels[2]);
getView().setLayoutParams(params);
}
}
protected void setMarginLeft(int margin) {
if (mView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mView.getLayoutParams();
if (mView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams params) {
params.leftMargin = margin;
}
}
protected void setMarginRight(int margin) {
if (mView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mView.getLayoutParams();
if (mView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams params) {
params.rightMargin = margin;
}
}
protected void setMarginTop(int margin) {
if (mView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mView.getLayoutParams();
if (mView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams params) {
params.topMargin = margin;
}
}
protected void setMarginBottom(int margin) {
if (mView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mView.getLayoutParams();
if (mView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams params) {
params.bottomMargin = margin;
@@ -452,15 +425,13 @@ public class ViewAttributes {
}
protected void setMarginStart(int margin) {
if (mView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mView.getLayoutParams();
if (mView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams params) {
params.setMarginStart(margin);
}
}
protected void setMarginEnd(int margin) {
if (mView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mView.getLayoutParams();
if (mView.getLayoutParams() instanceof ViewGroup.MarginLayoutParams params) {
params.setMarginEnd(margin);
}
}
@@ -474,27 +445,22 @@ public class ViewAttributes {
mView.setPadding(padding, mView.getPaddingTop(), mView.getPaddingRight(), mView.getPaddingBottom());
}
protected void setPaddingRight(int padding) {
mView.setPadding(mView.getPaddingLeft(), mView.getPaddingTop(), padding, mView.getPaddingBottom());
}
protected void setPaddingTop(int padding) {
mView.setPadding(mView.getPaddingLeft(), padding, mView.getPaddingRight(), mView.getPaddingBottom());
}
protected void setPaddingStart(int padding) {
mView.setPaddingRelative(padding, mView.getPaddingTop(), mView.getPaddingEnd(), mView.getPaddingBottom());
}
protected void setPaddingEnd(int padding) {
mView.setPaddingRelative(mView.getPaddingStart(), mView.getPaddingTop(), padding, mView.getPaddingBottom());
}
protected void setPaddingBottom(int padding) {
mView.setPadding(mView.getPaddingLeft(), mView.getPaddingTop(), mView.getPaddingRight(), padding);
}
@@ -504,9 +470,7 @@ public class ViewAttributes {
}
protected void setContextClickable(boolean clickable) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mView.setContextClickable(clickable);
}
mView.setContextClickable(clickable);
}
@@ -546,14 +510,12 @@ public class ViewAttributes {
}
}
protected void setWidth(int width) {
ViewGroup.LayoutParams layoutParams = mView.getLayoutParams();
layoutParams.width = width;
mView.setLayoutParams(layoutParams);
}
protected void setHeight(int height) {
ViewGroup.LayoutParams layoutParams = mView.getLayoutParams();
layoutParams.height = height;

View File

@@ -57,7 +57,6 @@ public class BlockedMaterialDialog extends MaterialDialog {
return false;
}
public static class Builder extends MaterialDialog.Builder {
private VolatileDispose<Object> mResultBox;

View File

@@ -1,15 +1,9 @@
package com.stardust.autojs.core.ui.dialog;
import android.content.Context;
import android.widget.EditText;
import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.GravityEnum;
import com.afollestad.materialdialogs.MaterialDialog;
import com.afollestad.materialdialogs.StackingBehavior;
import com.afollestad.materialdialogs.Theme;
import com.stardust.autojs.core.eventloop.EventEmitter;
import com.stardust.autojs.core.looper.Loopers;
import com.stardust.autojs.core.looper.Timer;
@@ -43,22 +37,22 @@ public class JsDialogBuilder extends MaterialDialog.Builder {
showListener(dialog -> emit("show", dialog));
onAny((dialog, which) -> {
switch (which) {
case NEUTRAL:
case NEUTRAL -> {
emit("neutral", dialog);
emit("any", "neutral", dialog);
break;
case NEGATIVE:
}
case NEGATIVE -> {
emit("negative", dialog);
emit("any", "negative", dialog);
break;
case POSITIVE:
}
case POSITIVE -> {
EditText editText = dialog.getInputEditText();
if (editText != null) {
emit("input", editText.getText().toString());
}
emit("positive", dialog);
emit("any", "positive", dialog);
break;
}
}
});
dismissListener(dialog -> {

View File

@@ -327,7 +327,7 @@ public class ScriptRuntime {
public static void requiresApi(int i) {
if (Build.VERSION.SDK_INT < i) {
throw new ScriptException(GlobalAppContext.getString(R.string.text_requires_sdk_version_to_run_the_script) + SdkVersionUtil.sdkIntToString(i));
throw new ScriptException(GlobalAppContext.getString(R.string.text_requires_sdk_version_to_run_the_script) + ": " + SdkVersionUtil.sdkIntToString(i));
}
}
@@ -447,6 +447,9 @@ public class ScriptRuntime {
return Continuation.Companion.create(this, scope);
}
public SimpleActionAutomator getAutomator() {
return automator;
}
public static String getStackTrace(Throwable e, boolean printJavaStackTrace) {
String message = e.getMessage();

View File

@@ -282,13 +282,13 @@ public class Device {
return;
}
SettingsCompat.manageWriteSettings(mContext);
throw new SecurityException(mContext.getString(R.string.no_write_settings_permission));
throw new SecurityException(mContext.getString(R.string.text_no_write_settings_permission));
}
private void checkReadPhoneStatePermission() {
if (mContext.checkSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
throw new SecurityException(mContext.getString(R.string.no_read_phone_state_permissin));
throw new SecurityException(mContext.getString(R.string.text_no_read_phone_state_permission));
}
}

View File

@@ -44,7 +44,7 @@ public class Dialogs {
MaterialDialog.Builder builder = dialogBuilder(callback)
.alert()
.title(title)
.positiveText(R.string.ok);
.positiveText(R.string.text_ok);
if (!TextUtils.isEmpty(content)) {
builder.content(content);
}
@@ -56,13 +56,13 @@ public class Dialogs {
MaterialDialog.Builder builder = dialogBuilder(callback)
.confirm()
.title(title)
.positiveText(R.string.ok)
.negativeText(R.string.cancel);
.positiveText(R.string.text_ok)
.negativeText(R.string.text_cancel);
if (!TextUtils.isEmpty(content)) {
builder.content(content);
}
return ((BlockedMaterialDialog.Builder) builder).showAndGet();
}
}
private Context getContext() {
if (mThemeWrapper != null)
@@ -76,33 +76,17 @@ public class Dialogs {
return ((BlockedMaterialDialog.Builder) dialogBuilder(callback)
.itemsCallback()
.title(title)
.items((CharSequence[]) items))
.items(items))
.showAndGet();
}
private String[] getItems(Object[] args) {
int len = 0;
if (args.length > 1) {
if (args[args.length - 1] instanceof CharSequence) {
len = args.length;
} else {
len = args.length - 1;
}
}
String[] items = new String[len];
for (int i = 0; i < len; i++) {
items[i] = args[i] == null ? null : args[i].toString();
}
return items;
}
@ScriptInterface
public Object singleChoice(String title, int selectedIndex, String[] items, Object callback) {
return ((BlockedMaterialDialog.Builder) dialogBuilder(callback)
.itemsCallbackSingleChoice(selectedIndex)
.title(title)
.positiveText(R.string.ok)
.items((CharSequence[]) items))
.positiveText(R.string.text_ok)
.items(items))
.showAndGet();
}
@@ -111,8 +95,8 @@ public class Dialogs {
return ((BlockedMaterialDialog.Builder) dialogBuilder(callback)
.itemsCallbackMultiChoice(ArrayUtils.box(indices))
.title(title)
.positiveText(R.string.ok)
.items((CharSequence[]) items))
.positiveText(R.string.text_ok)
.items(items))
.showAndGet();
}

View File

@@ -102,9 +102,13 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
if (mListeningKey)
return;
AccessibilityService service = getAccessibilityService();
if ((service.getServiceInfo().flags & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) == 0) {
throw new ScriptException(mContext.getString(R.string.text_should_enable_key_observing));
}
// @Dubious by SuperMonster003 as of Feb 11, 2022.
// ! condition may be always false ?
// if ((service.getServiceInfo().flags & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) == 0) {
// throw new ScriptException(mContext.getString(R.string.text_should_enable_key_observing));
// }
ensureHandler();
mLoopers.waitWhenIdle(true);
mListeningKey = true;
@@ -223,7 +227,7 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
mLoopers.waitWhenIdle(true);
if (NotificationListenerService.Companion.getInstance() == null) {
mContext.startActivity(new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS));
throw new ScriptException(mContext.getString(R.string.exception_notification_service_disabled));
throw new ScriptException(mContext.getString(R.string.text_notification_service_disabled));
}
NotificationListenerService.Companion.getInstance().addListener(this);
}

View File

@@ -75,6 +75,9 @@ public class Sensors extends EventEmitter implements Loopers.LooperQuitHandler {
public boolean ignoresUnsupportedSensor = false;
@SuppressWarnings("InstantiationOfUtilityClass")
public final Delay delay = new Delay();
private final Set<SensorEventEmitter> mSensorEventEmitters = new HashSet<>();
private final SensorManager mSensorManager;
private final ScriptBridges mScriptBridges;

View File

@@ -3,11 +3,9 @@ package com.stardust.autojs.util;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import androidx.annotation.RequiresApi;
import android.text.TextUtils;
import android.widget.Toast;
@@ -25,8 +23,6 @@ import ezy.assist.compat.SettingsCompat;
public class FloatingPermission {
private static final int OP_SYSTEM_ALERT_WINDOW = 24;
private static Method sCheckOp;
static {
@@ -71,8 +67,7 @@ public class FloatingPermission {
public static void manageDrawOverlays(Context context) {
try {
if (RomUtil.isMiui() && TextUtils.equals("V10", RomUtil.getVersion())
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (RomUtil.isMiui() && TextUtils.equals("V10", RomUtil.getVersion())) {
manageDrawOverlaysForAndroidM(context);
} else {
SettingsCompat.manageDrawOverlays(context);
@@ -82,7 +77,6 @@ public class FloatingPermission {
}
}
@RequiresApi(api = Build.VERSION_CODES.M)
public static void manageDrawOverlaysForAndroidM(Context context) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
intent.setData(Uri.parse("package:" + context.getPackageName()));
@@ -95,7 +89,7 @@ public class FloatingPermission {
private static boolean checkOp(Context context, int op) {
if (sCheckOp == null) {
return SettingsCompat.canDrawOverlays(context);
return canDrawOverlays(context);
}
try {
return (boolean) sCheckOp.invoke(null, context, op);

View File

@@ -0,0 +1,78 @@
package org.autojs.autojs.tool;
import android.widget.Toast;
import com.stardust.app.GlobalAppContext;
import com.stardust.autojs.R;
import com.stardust.autojs.core.util.ProcessShell;
import com.stericson.RootShell.RootShell;
/**
* Created by Stardust on 2018/1/26.
*/
public class RootTool {
private static final int POINTER_LOCATION_ENABLED = 1;
private static final int POINTER_LOCATION_DISABLED = 0;
public static boolean isRootAvailable() {
try {
return RootShell.isRootAvailable();
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public static boolean togglePointerLocation() {
try {
if (isPointerLocationEnabled()) {
setPointerLocationDisabled();
if (isPointerLocationDisabled()) {
return true;
}
} else {
setPointerLocationEnabled();
if (isPointerLocationEnabled()) {
return true;
}
}
} catch (Exception ignored) {
// Ignored.
}
GlobalAppContext.toast(GlobalAppContext.get().getString(R.string.text_pointer_location_toggle_failed_with_hint), Toast.LENGTH_LONG);
return false;
}
public static boolean isPointerLocationEnabled() {
return getPointerLocationResult() == POINTER_LOCATION_ENABLED;
}
public static boolean isPointerLocationDisabled() {
return getPointerLocationResult() == POINTER_LOCATION_DISABLED;
}
private static int getPointerLocationResult() {
// CAUTION
// ! result of execCommand() contains a "\n" and its length() is 2
return Integer.parseInt(ProcessShell.execCommand("settings get system pointer_location", true).result.trim());
}
public static boolean setPointerLocationEnabled() {
return setPointerLocationState(true);
}
public static boolean setPointerLocationDisabled() {
return setPointerLocationState(false);
}
private static boolean setPointerLocationState(boolean isEnabled) {
try {
ProcessShell.execCommand("settings put system pointer_location " + (isEnabled ? 1 : 0), true);
} catch (Exception ignored) {
return false;
}
return true;
}
}

View File

@@ -0,0 +1,57 @@
package org.autojs.autojs.tool;
import android.content.Context;
import android.content.pm.PackageManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.stardust.autojs.core.util.ProcessShell;
import java.text.MessageFormat;
public class SettingsTool {
public static class SecureSettings {
private static final String WRITE_SECURE_SETTINGS_PERMISSION = "android.permission.WRITE_SECURE_SETTINGS";
public static boolean isGranted(@Nullable Context context) {
if (context != null) {
int checkVal = context.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS_PERMISSION);
return checkVal == PackageManager.PERMISSION_GRANTED;
}
return false;
}
public static boolean grantAccess(Context context) {
return isGranted(context) && setAccessByAdb(context, true) ||
RootTool.isRootAvailable() && setAccessByRoot(context, true);
}
public static boolean revokeAccess(Context context) {
return isGranted(context) && setAccessByAdb(context, false) ||
RootTool.isRootAvailable() && setAccessByRoot(context, false);
}
private static boolean setAccessByRoot(Context context, boolean isGranted) {
ProcessShell.execCommand(getScript(context, isGranted), true);
return isGranted == isGranted(context);
}
private static boolean setAccessByAdb(Context context, boolean isGranted) {
ProcessShell.execCommand(getScript(context, isGranted), false);
return isGranted == isGranted(context);
}
@NonNull
private static String getScript(Context context, boolean isGranted) {
String scriptAction = isGranted ? "grant" : "revoke";
return MessageFormat.format("adb shell pm {0} {1} {2}",
scriptAction,
context.getPackageName(),
WRITE_SECURE_SETTINGS_PERMISSION);
}
}
}

View File

@@ -34,7 +34,7 @@
android:id="@+id/submit"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="@string/ok"
android:text="@string/text_ok"
android:textColor="@android:color/white"
android:theme="@style/ConsoleTheme"/>
</LinearLayout>

View File

@@ -1,21 +1,25 @@
<resources>
<string name="app_name">Auto.js</string>
<string name="text_error">Error:</string>
<string name="text_start_running">Script Running</string>
<string name="text_path_is_empty">Path is empty</string>
<string name="text_file_not_exists">File does not exist</string>
<string name="text_no_file_rw_permission">No file r/w permission</string>
<string name="text_no_running_scripts">No running scripts</string>
<string name="text_a11y_service_description">Required by the script automatic operation (click, long press, slide, etc.).</string>
<string name="text_already_stop_n_scripts">%d script(s) stopped</string>
<string name="text_requires_sdk_version_to_run_the_script">Required Android OS version:</string>
<string name="ok">OK</string>
<string name="cancel">Cancel</string>
<string name="text_cancel">Cancel</string>
<string name="text_console">Console</string>
<string name="text_no_floating_window_permission">No drawing overlay permission</string>
<string name="text_accessibility_service_description">Auto.js</string>
<string name="text_should_enable_key_observing">Key observing is disabled, please enable in settings</string>
<string name="no_write_settings_permission">No writing settings permission</string>
<string name="exception_notification_service_disabled">通知服务未运行,请重新启用通知权限</string>
<string name="text_drawer_close">Close drawer</string>
<string name="text_drawer_open">Open drawer</string>
<string name="text_file_not_exists">File doesn\'t exist</string>
<string name="text_notification_service_disabled">Notification service is not working</string>
<string name="text_no_read_phone_state_permission">No \"read phone state\" permission</string>
<string name="text_no_storage_rw_permission">No \"storage r/w\" permission</string>
<string name="text_no_write_settings_permission">No \"write settings\" permission</string>
<string name="text_ok">OK</string>
<string name="text_path_is_empty">Path is empty</string>
<string name="text_pointer_location_toggle_failed_with_hint">Toggle \"pointer location\" failed.\nRoot access is necessary.</string>
<string name="text_requires_sdk_version_to_run_the_script">Required Android OS version</string>
<string name="text_start_running">Running</string>
<string name="text_app_language_follow_system">Follow system</string>
<string name="text_app_language_english">English</string>
<string name="text_app_language_simplified_chinese">Simplified Chinese</string>
<string name="text_documentation_source_local">Local docs</string>
<string name="text_documentation_source_online">Online docs</string>
<string name="text_root_record_out_file_type_binary">Binary type (uneditable)</string>
<string name="text_root_record_out_file_type_js">JavaScript type (editable)</string>
</resources>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="text_a11y_service_description">脚本自动操作 (点击/长按/滑动等) 所需</string>
<string name="text_already_stop_n_scripts">已停止 %d 个正在运行的脚本</string>
<string name="text_cancel">取消</string>
<string name="text_console">控制台</string>
<string name="text_drawer_close">关闭侧拉抽屉</string>
<string name="text_drawer_open">打开侧拉抽屉</string>
<string name="text_file_not_exists">文件不存在</string>
<string name="text_notification_service_disabled">通知服务未运行</string>
<string name="text_no_read_phone_state_permission">缺少 \"读取手机状态\" 权限</string>
<string name="text_no_storage_rw_permission">缺少 \"读写存储空间\" 权限</string>
<string name="text_no_write_settings_permission">缺少 \"修改系統设置\" 权限</string>
<string name="text_ok">确定</string>
<string name="text_path_is_empty">路径为空</string>
<string name="text_pointer_location_toggle_failed_with_hint">\"指针位置\" 状态修改失败\n可能缺少 root 权限</string>
<string name="text_requires_sdk_version_to_run_the_script">需要的最低安卓版本</string>
<string name="text_start_running">开始运行</string>
<string name="text_app_language_follow_system">跟随系统</string>
<string name="text_app_language_english">英语</string>
<string name="text_app_language_simplified_chinese">简体中文</string>
<string name="text_documentation_source_local">本地文档</string>
<string name="text_documentation_source_online">在线文档</string>
<string name="text_root_record_out_file_type_binary">二进制文件 (不可编辑)</string>
<string name="text_root_record_out_file_type_js">JavaScript 文件 (可编辑)</string>
</resources>

View File

@@ -1,53 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="ad_showing_mode_keys">
<item>默认</item>
<item>每天显示一次</item>
<string-array name="keys_root_record_out_file_type">
<item>@string/text_root_record_out_file_type_binary</item>
<item>@string/text_root_record_out_file_type_js</item>
</string-array>
<string-array name="ad_showing_mode_values">
<item>Default</item>
<item>OncePerDay</item>
<string-array name="values_root_record_out_file_type">
<item>@string/value_root_record_out_file_type_binary</item>
<item>@string/value_root_record_out_file_type_js</item>
</string-array>
<string-array name="ad_types_keys">
<item>随机</item>
<item>新闻</item>
<item>社交</item>
<item>动漫</item>
<item>游戏</item>
</string-array>
<string-array name="ad_types_values">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
</string-array>
<string-array name="root_record_out_file_type_keys">
<item>可编辑的js文件</item>
<item>不可编辑的二进制文件</item>
</string-array>
<string-array name="root_record_out_file_type_values">
<item>js</item>
<item>binary</item>
</string-array>
<string-array name="keys_documentation_source">
<item>本地文档</item>
<item>在线文档</item>
<item>@string/text_documentation_source_local</item>
<item>@string/text_documentation_source_online</item>
</string-array>
<string-array name="values_documentation_source">
<item>Local</item>
<item>Online</item>
<item>@string/value_documentation_source_local</item>
<item>@string/value_documentation_source_online</item>
</string-array>
<string-array name="keys_app_language">
<item>@string/text_app_language_follow_system</item>
<item>@string/text_app_language_english</item>
<item>@string/text_app_language_simplified_chinese</item>
</string-array>
<string-array name="values_app_language">
<item>@string/value_app_language_default</item>
<item>@string/value_app_language_english</item>
<item>@string/value_app_language_simplified_chinese</item>
</string-array>
</resources>

View File

@@ -1,26 +1,34 @@
<resources>
<string name="app_name">Auto.js</string>
<string name="text_error">错误:</string>
<string name="text_start_running">开始运行</string>
<string name="text_path_is_empty">路径为空</string>
<string name="text_file_not_exists">文件不存在</string>
<string name="text_no_file_rw_permission">无文件读写权限</string>
<string name="text_no_running_scripts">没有正在运行的脚本</string>
<string name="text_already_stop_n_scripts">已停止 %d 个正在运行的脚本</string>
<string name="text_requires_sdk_version_to_run_the_script">本脚本需要此安卓版本以上才能运行:</string>
<string name="ok">确定</string>
<string name="cancel">取消</string>
<string name="text_console">控制台</string>
<string name="text_no_floating_window_permission">没有悬浮窗权限</string>
<string name="text_accessibility_service_description">使脚本自动操作(点击、长按、滑动等)所需,若关闭则只能执行不涉及自动操作的脚本。</string>
<string name="text_should_enable_key_observing">按键监听未启用,请在软件设置中开启</string>
<string name="text_should_enable_gesture_observing">手势监听未启用,请在软件设置中开启</string>
<string name="no_write_settings_permission">沒有修改系統设置权限</string>
<string name="exception_notification_service_disabled">通知服务未运行,请重新启用通知权限</string>
<string name="text_requires_app_version_to_run_the_script" formatted="true">本脚本需要Auto.js版本号%d以上才能运行</string>
<string name="text_drawer_open">打开侧拉菜单</string>
<string name="text_drawer_close">关闭侧拉菜单</string>
<string name="no_read_phone_state_permissin">没有读取设备信息权限</string>
<string name="text_a11y_service_description">Required by the script automatic operation (click, long press, slide, etc.).</string>
<string name="text_already_stop_n_scripts">%d script(s) stopped</string>
<string name="text_cancel">Cancel</string>
<string name="text_console">Console</string>
<string name="text_drawer_close">Close drawer</string>
<string name="text_drawer_open">Open drawer</string>
<string name="text_file_not_exists">File doesn\'t exist</string>
<string name="text_notification_service_disabled">Notification service is not working</string>
<string name="text_no_read_phone_state_permission">No \"read phone state\" permission</string>
<string name="text_no_storage_rw_permission">No \"storage r/w\" permission</string>
<string name="text_no_write_settings_permission">No \"write settings\" permission</string>
<string name="text_ok">OK</string>
<string name="text_path_is_empty">Path is empty</string>
<string name="text_pointer_location_toggle_failed_with_hint">Toggle \"pointer location\" failed.\nRoot access is necessary.</string>
<string name="text_requires_sdk_version_to_run_the_script">Required Android OS version</string>
<string name="text_start_running">Running</string>
<string name="value_app_language_default" translatable="false">@string/value_app_language_follow_system</string>
<string name="value_app_language_follow_system" translatable="false">Auto</string>
<string name="value_app_language_english" translatable="false">EN</string>
<string name="value_app_language_simplified_chinese" translatable="false">ZH_CN</string>
<string name="text_app_language_follow_system">Follow system</string>
<string name="text_app_language_english">English</string>
<string name="text_app_language_simplified_chinese">Simplified Chinese</string>
<string name="value_documentation_source_default" translatable="false">@string/value_documentation_source_local</string>
<string name="value_documentation_source_local" translatable="false">Local</string>
<string name="value_documentation_source_online" translatable="false">Online</string>
<string name="text_documentation_source_local">Local docs</string>
<string name="text_documentation_source_online">Online docs</string>
<string name="text_root_record_out_file_type_binary">Binary type (uneditable)</string>
<string name="text_root_record_out_file_type_js">JavaScript type (editable)</string>
<string name="value_root_record_out_file_type_binary" translatable="false">Binary</string>
<string name="value_root_record_out_file_type_js" translatable="false">JS</string>
</resources>

View File

@@ -7,5 +7,5 @@
android:canRequestEnhancedWebAccessibility="true"
android:canRequestFilterKeyEvents="true"
android:canRetrieveWindowContent="true"
android:description="@string/text_accessibility_service_description"
android:description="@string/text_a11y_service_description"
android:notificationTimeout="0"/>