6.0.3 - 新增使用修改安全设置权限自启无障碍 修复toast/socket导致崩溃 资源英文补全 支持64位系统 部分插件及工具版本更新
This commit is contained in:
@@ -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'
|
||||
|
||||
@@ -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" />
|
||||
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
module.exports = function(runtime, global){
|
||||
module.exports = function (runtime, global) {
|
||||
return Object.create(runtime.media);
|
||||
}
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
127
autojs/src/main/assets/modules/__recorder__.js
Normal file
127
autojs/src/main/assets/modules/__recorder__.js
Normal 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;
|
||||
|
||||
};
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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")));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -57,7 +57,6 @@ public class BlockedMaterialDialog extends MaterialDialog {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static class Builder extends MaterialDialog.Builder {
|
||||
|
||||
private VolatileDispose<Object> mResultBox;
|
||||
|
||||
@@ -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 -> {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
78
autojs/src/main/java/org/autojs/autojs/tool/RootTool.java
Normal file
78
autojs/src/main/java/org/autojs/autojs/tool/RootTool.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
26
autojs/src/main/res/values-zh/strings.xml
Normal file
26
autojs/src/main/res/values-zh/strings.xml
Normal 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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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"/>
|
||||
Reference in New Issue
Block a user