6.0.1 - Alpha - 增加全局Polyfill及扩展对象
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -2,6 +2,7 @@
|
||||
*.exe
|
||||
*.iml
|
||||
*.jks
|
||||
*.log
|
||||
|
||||
.DS_Store
|
||||
.externalNativeBuild
|
||||
@@ -18,4 +19,6 @@ output-metadata.json
|
||||
/tools/
|
||||
|
||||
/local.properties
|
||||
/sign.properties
|
||||
/sign.properties
|
||||
|
||||
**/assets/declarations/
|
||||
12
README.md
12
README.md
@@ -98,6 +98,18 @@
|
||||
|
||||
[comment]: <> "Version history only shows last 3 versions"
|
||||
|
||||
# v6.0.1 Alpha
|
||||
|
||||
###### 2021/12/05
|
||||
|
||||
* `新增` polyfill (Object.getOwnPropertyDescriptors)
|
||||
* `新增` polyfill (Array.prototype.flat)
|
||||
* `新增` isInteger/isNullish/isPlainObject/isPrimitive/isReference
|
||||
* `优化` 扩展global.sleep支持随机范围/负数兼容
|
||||
* `优化` 扩展global.toast支持时长控制/强制覆盖控制/dismiss方法
|
||||
* `优化` 包名对象全局化 (okhttp3/androidx/de)
|
||||
* `优化` 升级 Android Material 版本 1.5.0-beta01 -> 1.6.0-alpha01
|
||||
|
||||
# v6.0.0
|
||||
|
||||
###### 2021/12/01
|
||||
|
||||
@@ -115,6 +115,13 @@ android {
|
||||
buildConfigField "String", "APP_SINCE_DATE", "\"${versions.appSinceDate}\""
|
||||
}
|
||||
}
|
||||
applicationVariants.all { variant ->
|
||||
variant.mergeAssetsProvider.configure {
|
||||
doLast {
|
||||
delete(fileTree(dir: outputDir, includes: ['declarations/**']))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
@@ -138,7 +145,7 @@ dependencies {
|
||||
// Android supports
|
||||
implementation "androidx.appcompat:appcompat:1.4.0"
|
||||
implementation "androidx.cardview:cardview:1.0.0"
|
||||
implementation "com.google.android.material:material:1.5.0-beta01"
|
||||
implementation "com.google.android.material:material:1.6.0-alpha01"
|
||||
implementation "androidx.multidex:multidex:2.0.1"
|
||||
|
||||
// Material Dialogs
|
||||
|
||||
@@ -4,6 +4,18 @@
|
||||
|
||||
******
|
||||
|
||||
# v6.0.1 Alpha
|
||||
|
||||
###### 2021/12/05
|
||||
|
||||
* `新增` polyfill (Object.getOwnPropertyDescriptors)
|
||||
* `新增` polyfill (Array.prototype.flat)
|
||||
* `新增` isInteger/isNullish/isPlainObject/isPrimitive/isReference
|
||||
* `优化` 扩展global.sleep支持随机范围/负数兼容
|
||||
* `优化` 扩展global.toast支持时长控制/强制覆盖控制/dismiss方法
|
||||
* `优化` 包名对象全局化 (okhttp3/androidx/de)
|
||||
* `优化` 升级 Android Material 版本 1.5.0-beta01 -> 1.6.0-alpha01
|
||||
|
||||
# v6.0.0
|
||||
|
||||
###### 2021/12/01
|
||||
|
||||
@@ -49,7 +49,7 @@ public abstract class LayoutInspectTileService extends TileService implements La
|
||||
public void onClick() {
|
||||
super.onClick();
|
||||
Log.d(getClass().getName(), "onClick");
|
||||
sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
|
||||
// sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
|
||||
if (AccessibilityService.Companion.getInstance() == null) {
|
||||
Toast.makeText(this, R.string.text_no_accessibility_permission_to_capture, Toast.LENGTH_SHORT).show();
|
||||
AccessibilityServiceTool.goToAccessibilitySetting();
|
||||
@@ -83,7 +83,6 @@ public abstract class LayoutInspectTileService extends TileService implements La
|
||||
inactive();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
protected abstract FullScreenFloatyWindow onCreateWindow(NodeInfo capture);
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.stardust.app.GlobalAppContext;
|
||||
|
||||
import org.autojs.autojs.Pref;
|
||||
import org.autojs.autojs.R;
|
||||
|
||||
@@ -35,7 +36,7 @@ public class AccessibilityServiceTool {
|
||||
public static void goToAccessibilitySetting() {
|
||||
Context context = GlobalAppContext.get();
|
||||
if (Pref.isFirstGoToAccessibilitySetting()) {
|
||||
GlobalAppContext.toast(context.getString(R.string.text_please_choose) + context.getString(R.string.app_name));
|
||||
GlobalAppContext.toast(context.getString(R.string.text_please_choose) + " " + context.getString(R.string.app_name));
|
||||
}
|
||||
try {
|
||||
AccessibilityServiceUtils.INSTANCE.goToAccessibilitySetting(context);
|
||||
@@ -44,16 +45,18 @@ public class AccessibilityServiceTool {
|
||||
}
|
||||
}
|
||||
|
||||
private static final String cmd = "enabled=$(settings get secure enabled_accessibility_services)\n" +
|
||||
"pkg=%s\n" +
|
||||
"if [[ $enabled == *$pkg* ]]\n" +
|
||||
"then\n" +
|
||||
"echo already_enabled\n" +
|
||||
"else\n" +
|
||||
"enabled=$pkg:$enabled\n" +
|
||||
"settings put secure enabled_accessibility_services $enabled\n" +
|
||||
"fi\n" +
|
||||
"settings put secure accessibility_enabled 1";
|
||||
private static final String cmd = """
|
||||
enabled=$(settings get secure enabled_accessibility_services)
|
||||
pkg=%s
|
||||
if [[ $enabled == *$pkg* ]]
|
||||
then
|
||||
echo already_enabled
|
||||
else
|
||||
enabled=$pkg:$enabled
|
||||
settings put secure enabled_accessibility_services $enabled
|
||||
fi
|
||||
settings put secure accessibility_enabled 1
|
||||
""";
|
||||
|
||||
public static boolean enableAccessibilityServiceByRoot(Class<? extends android.accessibilityservice.AccessibilityService> accessibilityService) {
|
||||
String serviceName = GlobalAppContext.get().getPackageName() + "/" + accessibilityService.getName();
|
||||
|
||||
@@ -18,13 +18,15 @@ public class RootTool {
|
||||
}
|
||||
}
|
||||
|
||||
private static final String cmd = "enabled=$(settings get system pointer_location)\n" +
|
||||
"if [[ $enabled == 1 ]]\n" +
|
||||
"then\n" +
|
||||
"settings put system pointer_location 0\n" +
|
||||
"else\n" +
|
||||
"settings put system pointer_location 1\n" +
|
||||
"fi\n";
|
||||
private static final String cmd = """
|
||||
enabled=$(settings get system pointer_location)
|
||||
if [[ $enabled == 1 ]]
|
||||
then
|
||||
settings put system pointer_location 0
|
||||
else
|
||||
settings put system pointer_location 1
|
||||
fi
|
||||
""";
|
||||
|
||||
public static void togglePointerLocation() {
|
||||
try {
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
package org.autojs.autojs.tool;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonNull;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class SafeJsonElement extends JsonElement {
|
||||
private final JsonElement mJsonElement;
|
||||
|
||||
public SafeJsonElement(JsonElement jsonElement) {
|
||||
mJsonElement = jsonElement;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public JsonElement deepCopy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJsonArray() {
|
||||
return mJsonElement.isJsonArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJsonObject() {
|
||||
return mJsonElement.isJsonObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJsonPrimitive() {
|
||||
return mJsonElement.isJsonPrimitive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJsonNull() {
|
||||
return mJsonElement.isJsonNull();
|
||||
}
|
||||
|
||||
public JsonObject getAsJsonObject() {
|
||||
return mJsonElement.getAsJsonObject();
|
||||
}
|
||||
|
||||
public SafeJsonObject getAsSafeJsonObject() {
|
||||
try {
|
||||
return new SafeJsonObject(mJsonElement.getAsJsonObject());
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonArray getAsJsonArray() {
|
||||
return mJsonElement.getAsJsonArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonPrimitive getAsJsonPrimitive() {
|
||||
return mJsonElement.getAsJsonPrimitive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNull getAsJsonNull() {
|
||||
return mJsonElement.getAsJsonNull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getAsBoolean() {
|
||||
return mJsonElement.getAsBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number getAsNumber() {
|
||||
return mJsonElement.getAsNumber();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAsString() {
|
||||
return mJsonElement.getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getAsDouble() {
|
||||
return mJsonElement.getAsDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getAsFloat() {
|
||||
return mJsonElement.getAsFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getAsLong() {
|
||||
return mJsonElement.getAsLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAsInt() {
|
||||
return mJsonElement.getAsInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getAsByte() {
|
||||
return mJsonElement.getAsByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getAsCharacter() {
|
||||
return mJsonElement.getAsCharacter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getAsBigDecimal() {
|
||||
return mJsonElement.getAsBigDecimal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger getAsBigInteger() {
|
||||
return mJsonElement.getAsBigInteger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getAsShort() {
|
||||
return mJsonElement.getAsShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mJsonElement.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
package org.autojs.autojs.tool;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonNull;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class SafeJsonObject extends JsonElement {
|
||||
|
||||
private final JsonObject mJsonObject;
|
||||
|
||||
public SafeJsonObject(JsonObject jsonObject) {
|
||||
mJsonObject = jsonObject;
|
||||
}
|
||||
|
||||
public JsonObject deepCopy() {
|
||||
return mJsonObject.deepCopy();
|
||||
}
|
||||
|
||||
public void add(String property, JsonElement value) {
|
||||
mJsonObject.add(property, value);
|
||||
}
|
||||
|
||||
public JsonElement remove(String property) {
|
||||
return mJsonObject.remove(property);
|
||||
}
|
||||
|
||||
public void addProperty(String property, String value) {
|
||||
mJsonObject.addProperty(property, value);
|
||||
}
|
||||
|
||||
public void addProperty(String property, Number value) {
|
||||
mJsonObject.addProperty(property, value);
|
||||
}
|
||||
|
||||
public void addProperty(String property, Boolean value) {
|
||||
mJsonObject.addProperty(property, value);
|
||||
}
|
||||
|
||||
public void addProperty(String property, Character value) {
|
||||
mJsonObject.addProperty(property, value);
|
||||
}
|
||||
|
||||
public Set<Map.Entry<String, JsonElement>> entrySet() {
|
||||
return mJsonObject.entrySet();
|
||||
}
|
||||
|
||||
public Set<String> keySet() {
|
||||
return mJsonObject.keySet();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return mJsonObject.size();
|
||||
}
|
||||
|
||||
public boolean has(String memberName) {
|
||||
return mJsonObject.has(memberName);
|
||||
}
|
||||
|
||||
public JsonElement get(String memberName) {
|
||||
return mJsonObject.get(memberName);
|
||||
}
|
||||
|
||||
public JsonPrimitive getAsJsonPrimitive(String memberName) {
|
||||
return mJsonObject.getAsJsonPrimitive(memberName);
|
||||
}
|
||||
|
||||
public JsonArray getAsJsonArray(String memberName) {
|
||||
return mJsonObject.getAsJsonArray(memberName);
|
||||
}
|
||||
|
||||
public JsonObject getAsJsonObject(String memberName) {
|
||||
return mJsonObject.getAsJsonObject(memberName);
|
||||
}
|
||||
|
||||
public boolean isJsonArray() {
|
||||
return mJsonObject.isJsonArray();
|
||||
}
|
||||
|
||||
public boolean isJsonObject() {
|
||||
return mJsonObject.isJsonObject();
|
||||
}
|
||||
|
||||
public boolean isJsonPrimitive() {
|
||||
return mJsonObject.isJsonPrimitive();
|
||||
}
|
||||
|
||||
public boolean isJsonNull() {
|
||||
return mJsonObject.isJsonNull();
|
||||
}
|
||||
|
||||
public JsonObject getAsJsonObject() {
|
||||
return mJsonObject.getAsJsonObject();
|
||||
}
|
||||
|
||||
public JsonArray getAsJsonArray() {
|
||||
return mJsonObject.getAsJsonArray();
|
||||
}
|
||||
|
||||
public JsonPrimitive getAsJsonPrimitive() {
|
||||
return mJsonObject.getAsJsonPrimitive();
|
||||
}
|
||||
|
||||
public JsonNull getAsJsonNull() {
|
||||
return mJsonObject.getAsJsonNull();
|
||||
}
|
||||
|
||||
public boolean getAsBoolean() {
|
||||
return mJsonObject.getAsBoolean();
|
||||
}
|
||||
|
||||
public Number getAsNumber() {
|
||||
return mJsonObject.getAsNumber();
|
||||
}
|
||||
|
||||
public String getAsString() {
|
||||
return mJsonObject.getAsString();
|
||||
}
|
||||
|
||||
public double getAsDouble() {
|
||||
return mJsonObject.getAsDouble();
|
||||
}
|
||||
|
||||
public float getAsFloat() {
|
||||
return mJsonObject.getAsFloat();
|
||||
}
|
||||
|
||||
public long getAsLong() {
|
||||
return mJsonObject.getAsLong();
|
||||
}
|
||||
|
||||
public int getAsInt() {
|
||||
return mJsonObject.getAsInt();
|
||||
}
|
||||
|
||||
public byte getAsByte() {
|
||||
return mJsonObject.getAsByte();
|
||||
}
|
||||
|
||||
public char getAsCharacter() {
|
||||
return mJsonObject.getAsCharacter();
|
||||
}
|
||||
|
||||
public BigDecimal getAsBigDecimal() {
|
||||
return mJsonObject.getAsBigDecimal();
|
||||
}
|
||||
|
||||
public BigInteger getAsBigInteger() {
|
||||
return mJsonObject.getAsBigInteger();
|
||||
}
|
||||
|
||||
public short getAsShort() {
|
||||
return mJsonObject.getAsShort();
|
||||
}
|
||||
}
|
||||
@@ -2,36 +2,36 @@ package org.autojs.autojs.tool;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.DhcpInfo;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.text.format.Formatter;
|
||||
import android.util.Log;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.net.InetAddress;
|
||||
|
||||
import static android.content.Context.WIFI_SERVICE;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/5/11.
|
||||
*/
|
||||
|
||||
public class WifiTool {
|
||||
|
||||
public static String getWifiAddress(Context context) {
|
||||
WifiManager wifiMgr = (WifiManager) context.getApplicationContext().getSystemService(WIFI_SERVICE);
|
||||
if(wifiMgr == null){
|
||||
return null;
|
||||
public static String getRouterIp(Context context) {
|
||||
byte[] ipAddressByte = getIpAddressByte(context);
|
||||
try {
|
||||
return InetAddress.getByAddress(ipAddressByte).getHostAddress();
|
||||
} catch (UnknownHostException e) {
|
||||
Log.e(WifiTool.class.getSimpleName(), "Error getting Hotspot IP address ", e);
|
||||
return "0.0.0.0";
|
||||
}
|
||||
WifiInfo wifiInfo = wifiMgr.getConnectionInfo();
|
||||
int ip = wifiInfo.getIpAddress();
|
||||
return Formatter.formatIpAddress(ip);
|
||||
}
|
||||
|
||||
public static String getRouterIp(Context context){
|
||||
WifiManager wifiService = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
|
||||
if(wifiService == null){
|
||||
return null;
|
||||
private static byte[] getIpAddressByte(Context context) {
|
||||
WifiManager manager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
|
||||
DhcpInfo dhcp = manager.getDhcpInfo();
|
||||
int ipAddress = dhcp.gateway;
|
||||
if (ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN)) {
|
||||
ipAddress = Integer.reverseBytes(ipAddress);
|
||||
}
|
||||
DhcpInfo dhcpInfo = wifiService.getDhcpInfo();
|
||||
return Formatter.formatIpAddress(dhcpInfo.gateway);
|
||||
return BigInteger.valueOf(ipAddress).toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,15 +155,14 @@ public class CircularMenu implements Recorder.OnStateChangedListener, LayoutInsp
|
||||
mWindow.collapse();
|
||||
if (!RootTool.isRootAvailable()) {
|
||||
DialogUtils.showDialog(new NotAskAgainDialog.Builder(mContext, "CircularMenu.root")
|
||||
.title(R.string.text_device_not_rooted)
|
||||
.content(R.string.prompt_device_not_rooted)
|
||||
.neutralText(R.string.text_device_rooted)
|
||||
.positiveText(R.string.ok)
|
||||
.onNeutral(((dialog, which) -> mRecorder.start()))
|
||||
.title(R.string.text_no_root_access)
|
||||
.content(R.string.no_root_access_for_record)
|
||||
.negativeText(R.string.text_quit)
|
||||
.positiveText(R.string.text_insist_on_record)
|
||||
.onPositive(((dialog, which) -> mRecorder.start()))
|
||||
.build());
|
||||
} else {
|
||||
mRecorder.start();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -155,9 +155,7 @@ public class DrawerFragment extends androidx.fragment.app.Fragment {
|
||||
if (checked && !isAccessibilityServiceEnabled) {
|
||||
enableAccessibilityService();
|
||||
} else if (!checked && isAccessibilityServiceEnabled) {
|
||||
if (!AccessibilityService.Companion.disable()) {
|
||||
AccessibilityServiceTool.goToAccessibilitySetting();
|
||||
}
|
||||
disableAccessibilityService();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,26 +175,27 @@ public class DrawerFragment extends androidx.fragment.app.Fragment {
|
||||
}
|
||||
boolean checked = holder.getSwitchCompat().isChecked();
|
||||
if (checked && !enabled) {
|
||||
if (new NotAskAgainDialog.Builder(context, "DrawerFragment.usage_stats")
|
||||
.title(R.string.text_usage_stats_permission)
|
||||
.content(R.string.description_usage_stats_permission)
|
||||
.positiveText(R.string.ok)
|
||||
.dismissListener(dialog -> {
|
||||
if (context != null) {
|
||||
IntentUtil.requestAppUsagePermission(context);
|
||||
}
|
||||
})
|
||||
.show() == null) {
|
||||
if (context != null) {
|
||||
IntentUtil.requestAppUsagePermission(context);
|
||||
}
|
||||
if (getUsageStatsDialog(context) == null) {
|
||||
syncSwitchState();
|
||||
}
|
||||
}
|
||||
if (!checked && enabled) {
|
||||
} else if (!checked && enabled) {
|
||||
IntentUtil.requestAppUsagePermission(context);
|
||||
}
|
||||
}
|
||||
|
||||
private MaterialDialog getUsageStatsDialog(Context context) {
|
||||
return new NotAskAgainDialog.Builder(context, "DrawerFragment.usage_stats")
|
||||
.title(R.string.text_usage_stats_permission)
|
||||
.content(R.string.description_usage_stats_permission)
|
||||
.positiveText(R.string.ok)
|
||||
.dismissListener(dialog -> {
|
||||
if (context != null) {
|
||||
IntentUtil.requestAppUsagePermission(context);
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
void showOrDismissFloatingWindow(DrawerMenuItemViewHolder holder) {
|
||||
boolean isFloatingWindowShowing = FloatyWindowManger.isCircularMenuShowing();
|
||||
boolean checked = holder.getSwitchCompat().isChecked();
|
||||
@@ -273,6 +272,7 @@ public class DrawerFragment extends androidx.fragment.app.Fragment {
|
||||
private boolean hasWriteSecureSettingsAccess() {
|
||||
Context context = getContext();
|
||||
if (context != null) {
|
||||
@SuppressLint("WrongConstant")
|
||||
int checkVal = context.checkCallingOrSelfPermission(WRITE_SECURE_SETTINGS_PERMISSION);
|
||||
return checkVal == PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
@@ -373,7 +373,7 @@ public class DrawerFragment extends androidx.fragment.app.Fragment {
|
||||
Observable.fromCallable(() -> Pref.shouldEnableAccessibilityServiceByRoot() && !isAccessibilityServiceEnabled())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(needed -> {
|
||||
if (needed) {
|
||||
if (needed && RootTool.isRootAvailable()) {
|
||||
enableAccessibilityServiceByRoot();
|
||||
}
|
||||
});
|
||||
@@ -457,11 +457,17 @@ public class DrawerFragment extends androidx.fragment.app.Fragment {
|
||||
}
|
||||
|
||||
private void enableAccessibilityService() {
|
||||
if (!Pref.shouldEnableAccessibilityServiceByRoot()) {
|
||||
if (Pref.shouldEnableAccessibilityServiceByRoot() && RootTool.isRootAvailable()) {
|
||||
enableAccessibilityServiceByRoot();
|
||||
} else {
|
||||
AccessibilityServiceTool.goToAccessibilitySetting();
|
||||
}
|
||||
}
|
||||
|
||||
private void disableAccessibilityService() {
|
||||
if (!AccessibilityService.Companion.disable()) {
|
||||
AccessibilityServiceTool.goToAccessibilitySetting();
|
||||
return;
|
||||
}
|
||||
enableAccessibilityServiceByRoot();
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
<string name="text_error">Error</string>
|
||||
<string name="text_copy_debug_info">Copy debugging log</string>
|
||||
<string name="text_it_is_the_developer_of_app">This is a software developer(。・・)ノ</string>
|
||||
<string name="text_please_choose">Please choose </string>
|
||||
<string name="text_please_choose">Please choose</string>
|
||||
<string name="text_crash">Crash~ o(≧□≦)o</string>
|
||||
<string name="crash_feedback">(ಥ _ ಥ)Exit or submit a bug report or copy debugging log to the developer(≧∇≦)ノ</string>
|
||||
<string name="text_clear">Clear</string>
|
||||
@@ -182,6 +182,7 @@
|
||||
<string name="text_stable_mode">Stable mode</string>
|
||||
<string name="text_foreground_service">Foreground service</string>
|
||||
<string name="text_usage_stats_permission">Usage stats access</string>
|
||||
<string name="description_usage_stats_permission">Provides access to device usage history and statistics which results in currentPackage() a more accurate result</string>
|
||||
<string name="text_volume_down_control">Volume down control</string>
|
||||
<string name="text_task">Task</string>
|
||||
<string name="text_next_run_time">Next</string>
|
||||
@@ -238,6 +239,7 @@
|
||||
<string name="text_time">Time</string>
|
||||
<string name="text_size">Size</string>
|
||||
<string name="text_type">Type</string>
|
||||
<string name="text_icon">Icon</string>
|
||||
<string name="text_js_file">*.js file</string>
|
||||
<string name="text_notification_permission">Notification access</string>
|
||||
<string name="text_permission">Permission</string>
|
||||
@@ -253,4 +255,8 @@
|
||||
<string name="text_failed">Failed</string>
|
||||
<string name="mt_color_picker_title">Color picker</string>
|
||||
<string name="mt_custom">Custom</string>
|
||||
<string name="text_no_root_access">No root access</string>
|
||||
<string name="no_root_access_for_record">Auto.js has no root access to record a script. Continue?</string>
|
||||
<string name="text_insist_on_record">Record</string>
|
||||
<string name="text_quit">Quit</string>
|
||||
</resources>
|
||||
|
||||
@@ -311,9 +311,9 @@
|
||||
<string name="format_default_package_name" formatted="true">com.example.script%d</string>
|
||||
<string name="text_should_not_be_empty">不能为空</string>
|
||||
<string name="text_icon">图标</string>
|
||||
<string name="text_device_not_rooted">设备没有root</string>
|
||||
<string name="prompt_device_not_rooted">监测到您的设备没有root, 录制脚本需要root权限, 是否继续?</string>
|
||||
<string name="text_device_rooted">仍要录制</string>
|
||||
<string name="text_no_root_access">无root权限</string>
|
||||
<string name="no_root_access_for_record">Auto.js无root权限, 录制脚本需root权限, 是否继续录制</string>
|
||||
<string name="text_insist_on_record">录制</string>
|
||||
<string name="nodebb_error_invalid_login_credentials">无效的登录凭证</string>
|
||||
<string name="nodebb_error_change_password_error_length">密码太短</string>
|
||||
<string name="nodebb_error_email_taken">邮箱已被占用</string>
|
||||
@@ -393,7 +393,7 @@
|
||||
<string name="text_run_on_package_update">应用更新时</string>
|
||||
<string name="text_run_on_headset_plug">耳机插拔时</string>
|
||||
<string name="text_run_on_time_tick">每分钟一次</string>
|
||||
<string name="text_run_on_config_change">某些设置(屏幕方向,地区等)更改时</string>
|
||||
<string name="text_run_on_config_change">某些设置 (屏幕方向, 地区等) 更改时</string>
|
||||
<string name="error_pattern_syntax">正则表达式错误</string>
|
||||
<string name="text_invalid_package_name">非法包名</string>
|
||||
<string name="error_cannot_rename">重命名失败</string>
|
||||
@@ -403,7 +403,7 @@
|
||||
<string name="key_night_mode">key_night_mode</string>
|
||||
<string name="text_run_on_startup">Auto.js启动时</string>
|
||||
<string name="text_usage_stats_permission">查看使用情况权限</string>
|
||||
<string name="description_usage_stats_permission">通过\"查看使用情况\"权限可以获取本设备过去使用应用的情况,从而使获取当前应用(currentPackage)时更准确。</string>
|
||||
<string name="description_usage_stats_permission">通过\"查看使用情况\"权限可获取本设备过去使用应用的情况, 从而使\"获取当前应用\" (currentPackage) 结果更准确</string>
|
||||
<string name="text_open_with">打开方式</string>
|
||||
<string name="text_root">Root</string>
|
||||
<string name="text_no_root">免Root</string>
|
||||
@@ -421,4 +421,5 @@
|
||||
<string name="text_failed">失败</string>
|
||||
<string name="mt_color_picker_title">选择颜色</string>
|
||||
<string name="mt_custom">自定义</string>
|
||||
<string name="text_quit">放弃</string>
|
||||
</resources>
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
<string name="text_assist_clip">点击定位剪贴板</string>
|
||||
<string name="text_script_stopped">Script stopped</string>
|
||||
<string name="assist_mode_notice">(不会翻译)\"点击区域辅助服务\"是在要点击的区域不是文本时使用的,参见\"语法与API\"。\"点击区域辅助服务\"只有在\"自动操作服务\"开启时才有效。</string>
|
||||
<string name="text_please_choose">Please choose</string>
|
||||
<string name="text_please_choose">请选择</string>
|
||||
<string name="text_crash">崩溃了o(≧□≦)o</string>
|
||||
<string name="crash_feedback">(不会翻译)点击\"退出\"退出程序(ಥ _ ಥ)或者提交错误报告或者复制调试信息反馈给开发者(≧∇≦)ノ</string>
|
||||
<string name="text_cannot_create_dialog_when_app_invisible">无法在后台显示弹框,脚本已停止运行</string>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
plugins {
|
||||
id "com.android.library"
|
||||
id "kotlin-android"
|
||||
}
|
||||
|
||||
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
|
||||
kotlinOptions {
|
||||
@@ -45,8 +47,8 @@ dependencies {
|
||||
|
||||
api 'net.lingala.zip4j:zip4j:2.9.1'
|
||||
|
||||
api('com.afollestad.material-dialogs:core:0.9.6.0')
|
||||
api 'com.google.android.material:material:1.5.0-beta01'
|
||||
api 'com.afollestad.material-dialogs:core:0.9.6.0'
|
||||
api 'com.google.android.material:material:1.6.0-alpha01'
|
||||
|
||||
api 'com.github.hyb1996:EnhancedFloaty:0.31'
|
||||
|
||||
|
||||
@@ -1,37 +1,31 @@
|
||||
var global = this;
|
||||
let global = this;
|
||||
|
||||
runtime.init();
|
||||
|
||||
(function () {
|
||||
//重定向importClass使得其支持字符串参数
|
||||
global.importClass =
|
||||
(function () {
|
||||
var __importClass__ = importClass;
|
||||
return function (pack) {
|
||||
if (typeof (pack) == "string") {
|
||||
__importClass__(Packages[pack]);
|
||||
} else {
|
||||
__importClass__(pack);
|
||||
}
|
||||
}
|
||||
})();
|
||||
!function () {
|
||||
// 重定向 importClass 使其支持字符串参数
|
||||
global.importClass = (function () {
|
||||
let __importClass__ = importClass;
|
||||
return function (pack) {
|
||||
__importClass__(typeof pack === 'string' ? Packages[pack] : pack);
|
||||
};
|
||||
})();
|
||||
|
||||
//内部函数
|
||||
global.__asGlobal__ = function (obj, functions) {
|
||||
var len = functions.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
var funcName = functions[i];
|
||||
var func = obj[funcName]
|
||||
if (!func) {
|
||||
continue;
|
||||
var func = obj[funcName];
|
||||
if (func) {
|
||||
(function (obj, funcName, func) {
|
||||
global[funcName] = function () {
|
||||
return func.apply(obj, arguments);
|
||||
};
|
||||
})(obj, funcName, func);
|
||||
}
|
||||
(function (obj, funcName, func) {
|
||||
global[funcName] = function () {
|
||||
return func.apply(obj, arguments);
|
||||
};
|
||||
})(obj, funcName, func);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
global.__exitIfError__ = function (action, defReturnValue) {
|
||||
try {
|
||||
@@ -40,7 +34,7 @@ runtime.init();
|
||||
if (err instanceof java.lang.Throwable) {
|
||||
exit(err);
|
||||
} else if (err instanceof Error) {
|
||||
exit(new org.mozilla.javascript.EvaluatorException(err.name + ": " + err.message, err.fileName, err.lineNumber));
|
||||
exit(new org.mozilla.javascript.EvaluatorException(err.name + ': ' + err.message, err.fileName, err.lineNumber));
|
||||
} else {
|
||||
exit();
|
||||
}
|
||||
@@ -48,25 +42,28 @@ runtime.init();
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化基础模块
|
||||
global.timers = require('__timers__.js')(runtime, global);
|
||||
// 初始化基础模块
|
||||
global.timers = require('__timers__.js')(runtime, global);
|
||||
|
||||
//初始化不依赖环境的模块
|
||||
global.JSON = require('json2.js');
|
||||
global.util = require('__util__.js');
|
||||
global.device = runtime.device;
|
||||
global.Promise = require('promise.js');
|
||||
|
||||
//设置JavaScriptBridges用于与Java层的交互和数据转换
|
||||
runtime.bridges.setBridges(require('__bridges__.js'));
|
||||
//初始化不依赖环境的模块
|
||||
global.JSON = require('json2.js');
|
||||
global.util = require('__util__.js');
|
||||
global.device = runtime.device;
|
||||
global.Promise = require('promise.js');
|
||||
|
||||
//设置JavaScriptBridges用于与Java层的交互和数据转换
|
||||
runtime.bridges.setBridges(require('__bridges__.js'));
|
||||
|
||||
//初始化全局函数
|
||||
require("__globals__")(runtime, global);
|
||||
require('__globals__')(runtime, global);
|
||||
|
||||
require('custom-polyfill').fill();
|
||||
|
||||
//初始化一般模块
|
||||
(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"];
|
||||
'images', 'threads', 'events', 'engines', 'RootAutomator', 'http', 'storages', 'floaty',
|
||||
'sensors', 'media', 'plugins', 'continuation'];
|
||||
var len = modules.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
var m = modules[i];
|
||||
@@ -74,17 +71,14 @@ runtime.init();
|
||||
}
|
||||
})(global);
|
||||
|
||||
importClass(android.view.KeyEvent);
|
||||
importClass(com.stardust.autojs.core.util.Shell);
|
||||
importClass(android.graphics.Paint);
|
||||
KeyEvent = android.view.KeyEvent;
|
||||
Shell = com.stardust.autojs.core.util.Shell;
|
||||
Paint = android.graphics.Paint;
|
||||
|
||||
Canvas = com.stardust.autojs.core.graphics.ScriptCanvas;
|
||||
Image = com.stardust.autojs.core.image.ImageWrapper;
|
||||
|
||||
//重定向require以便支持相对路径和npm模块
|
||||
Module = require("jvm-npm.js");
|
||||
// 重定向require以便支持相对路径和npm模块
|
||||
Module = require('jvm-npm.js');
|
||||
require = Module.require;
|
||||
|
||||
|
||||
})();
|
||||
|
||||
|
||||
}();
|
||||
@@ -1,145 +1,266 @@
|
||||
let Looper = android.os.Looper;
|
||||
let Toast = android.widget.Toast;
|
||||
let Runnable = java.lang.Runnable;
|
||||
|
||||
module.exports = function(runtime, global){
|
||||
global.toast = function(text){
|
||||
runtime.toast(text);
|
||||
}
|
||||
|
||||
global.toastLog = function(text){
|
||||
runtime.toast(text);
|
||||
global.log(text);
|
||||
}
|
||||
|
||||
global.sleep = function(t) {
|
||||
if(ui.isUiThread()){
|
||||
throw new Error("不能在ui线程执行阻塞操作,请使用setTimeout代替");
|
||||
}
|
||||
runtime.sleep(t);
|
||||
}
|
||||
|
||||
global.isStopped = function(){
|
||||
return runtime.isStopped();
|
||||
}
|
||||
|
||||
global.isShuttingDown = global.isShopped;
|
||||
|
||||
global.notStopped = function(){
|
||||
return !isStopped();
|
||||
}
|
||||
|
||||
global.isRunning = global.notStopped;
|
||||
|
||||
global.exit = runtime.exit.bind(runtime);
|
||||
|
||||
global.stop = global.exit;
|
||||
|
||||
global.setClip = function(text){
|
||||
runtime.setClip(text);
|
||||
}
|
||||
|
||||
global.getClip = function(text){
|
||||
return runtime.getClip();
|
||||
}
|
||||
|
||||
global.currentPackage = function(){
|
||||
global.auto();
|
||||
return runtime.info.getLatestPackage();
|
||||
}
|
||||
|
||||
global.currentActivity = function(){
|
||||
global.auto();
|
||||
return runtime.info.getLatestActivity();
|
||||
}
|
||||
|
||||
global.waitForActivity = function(activity, period){
|
||||
ensureNonUiThread();
|
||||
period = period || 200;
|
||||
while(global.currentActivity() != activity){
|
||||
sleep(period);
|
||||
}
|
||||
}
|
||||
|
||||
global.waitForPackage = function(packageName, period){
|
||||
ensureNonUiThread();
|
||||
period = period || 200;
|
||||
while(global.currentPackage() != packageName){
|
||||
sleep(period);
|
||||
}
|
||||
}
|
||||
|
||||
function ensureNonUiThread() {
|
||||
if(ui.isUiThread()){
|
||||
throw new Error("不能在ui线程执行阻塞操作,请在子线程或子脚本执行,或者使用setInterval循环检测当前activity和package");
|
||||
}
|
||||
}
|
||||
|
||||
global.random = function(min, max){
|
||||
if(arguments.length == 0){
|
||||
return Math.random();
|
||||
}
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
global.setScreenMetrics = runtime.setScreenMetrics.bind(runtime);
|
||||
|
||||
global.requiresApi = runtime.requiresApi.bind(runtime);
|
||||
global.requiresAutojsVersion = function(version){
|
||||
if(typeof(version) == 'number'){
|
||||
if(compare(version, app.autojs.versionCode) > 0){
|
||||
throw new Error("需要Auto.js版本号" + version + "以上才能运行");
|
||||
module.exports = function (runtime, global) {
|
||||
let _ = {
|
||||
buildTypes: {
|
||||
release: 100, beta: 50, alpha: 0,
|
||||
},
|
||||
ensureNonUiThread() {
|
||||
if (ui.isUiThread()) {
|
||||
throw new Error('不能在ui线程执行阻塞操作,请在子线程或子脚本执行,或者使用setInterval循环检测当前activity和package');
|
||||
}
|
||||
}else{
|
||||
if(compareVersion(version, app.autojs.versionName) > 0){
|
||||
throw new Error("需要Auto.js版本" + version + "以上才能运行");
|
||||
},
|
||||
compareVersion(v1, v2) {
|
||||
v1 = this.parseVersion(v1);
|
||||
v2 = this.parseVersion(v2);
|
||||
if (v1.major !== v2.major) {
|
||||
return this.compare(v1.major, v2.major);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (v1.minor !== v2.minor) {
|
||||
return this.compare(v1.minor, v2.minor);
|
||||
}
|
||||
if (v1.revision !== v2.revision) {
|
||||
return this.compare(v1.revision, v2.revision);
|
||||
}
|
||||
if (v1.buildType !== v2.buildType) {
|
||||
return this.compare(v1.buildType, v2.buildType);
|
||||
}
|
||||
return this.compare(v1.build, v2.build);
|
||||
},
|
||||
compare(a, b) {
|
||||
return a > b ? 1 : a < b ? -1 : 0;
|
||||
},
|
||||
parseVersion(v) {
|
||||
const m = /(\d+)\.(\d+)\.(\d+)[ ]?(Alpha|Beta)?(\d*)/.exec(v);
|
||||
if (!m) {
|
||||
throw new Error('版本格式不合法: ' + v);
|
||||
}
|
||||
return {
|
||||
major: parseInt(m[1]),
|
||||
minor: parseInt(m[2]),
|
||||
revision: parseInt(m[3]),
|
||||
buildType: _.buildType(m[4]),
|
||||
build: m[5] ? parseInt(m[5]) : 1,
|
||||
};
|
||||
},
|
||||
buildType(str) {
|
||||
if (str === 'Alpha') {
|
||||
return this.buildTypes.alpha;
|
||||
}
|
||||
if (str === 'Beta') {
|
||||
return this.buildTypes.beta;
|
||||
}
|
||||
return this.buildTypes.release;
|
||||
},
|
||||
};
|
||||
|
||||
var buildTypes = {
|
||||
release: 100,
|
||||
beta: 50,
|
||||
alpha: 0
|
||||
}
|
||||
Object.assign(global, {
|
||||
de: Packages.de,
|
||||
okhttp3: Packages.okhttp3,
|
||||
androidx: Packages.androidx,
|
||||
toast(msg, is_long, is_forcible) {
|
||||
let $ = {
|
||||
cache: null,
|
||||
toast(msg, is_long, is_forcible) {
|
||||
this.init(arguments);
|
||||
this.post();
|
||||
},
|
||||
/** @param {IArguments} args */
|
||||
init(args) {
|
||||
let [msg, is_long, is_forcible] = args;
|
||||
this.message = isNullish(msg) ? '' : msg.toString();
|
||||
this.is_long = this.parseIsLong(is_long);
|
||||
this.is_forcible = is_forcible;
|
||||
},
|
||||
post() {
|
||||
ui.post(() => {
|
||||
new android.os.Handler(Looper.getMainLooper()).post(new Runnable({
|
||||
run() {
|
||||
$.is_forcible && $.dismiss();
|
||||
$.cache = Toast.makeText(context, $.message, $.is_long);
|
||||
$.show();
|
||||
},
|
||||
}));
|
||||
});
|
||||
},
|
||||
parseIsLong(is_long) {
|
||||
if (typeof is_long === 'number') {
|
||||
return Number(!!is_long);
|
||||
}
|
||||
if (typeof is_long === 'string') {
|
||||
return Number(/^l(ong)?$/i.test(is_long));
|
||||
}
|
||||
if (typeof is_long === 'boolean') {
|
||||
return Number(is_long);
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
dismiss() {
|
||||
if (this.cache instanceof Toast) {
|
||||
this.cache.cancel();
|
||||
this.cache = null;
|
||||
}
|
||||
},
|
||||
show() {
|
||||
this.cache.show();
|
||||
},
|
||||
};
|
||||
|
||||
function compareVersion(v1, v2){
|
||||
v1 = parseVersion(v1);
|
||||
v2 = parseVersion(v2);
|
||||
log(v1, v2);
|
||||
return v1.major != v2.major ? compare(v1.major, v2.major) :
|
||||
v1.minor != v2.minor ? compare(v1.minor, v2.minor) :
|
||||
v1.revision != v2.revision ? compare(v1.revision, v2.revision) :
|
||||
v1.buildType != v2.buildType ? compare(v1.buildType, v2.buildType) :
|
||||
compare(v1.build, v2.build);
|
||||
}
|
||||
(function $LazY() {
|
||||
this.toast = $.toast.bind($);
|
||||
this.toast.dismiss = () => $.dismiss();
|
||||
return this.toast;
|
||||
}).apply(this, arguments);
|
||||
},
|
||||
toastLog(msg, is_long, is_forcible) {
|
||||
this.toast.apply(this, arguments);
|
||||
this.log(msg);
|
||||
},
|
||||
sleep(millis_min, millis_max) {
|
||||
let $ = {
|
||||
rex_num: /[+-]?(\d+(\.\d+)?(e\d+)?)/,
|
||||
set min(v) {
|
||||
this._min = Number(v);
|
||||
},
|
||||
get min() {
|
||||
return Math.max(this._min, 0);
|
||||
},
|
||||
set max(v) {
|
||||
this._max = Number(v);
|
||||
},
|
||||
get max() {
|
||||
return Math.min(this._max, Number.MAX_SAFE_INTEGER);
|
||||
},
|
||||
sleep(min, max) {
|
||||
if (this.trigger()) {
|
||||
this.parseArgs(min, max);
|
||||
runtime.sleep(this.min + this.rand_bound);
|
||||
}
|
||||
},
|
||||
trigger() {
|
||||
if (ui.isUiThread()) {
|
||||
throw Error('不能在ui线程执行阻塞操作,请使用setTimeout代替');
|
||||
}
|
||||
return true;
|
||||
},
|
||||
parseArgs(min, max) {
|
||||
this.parseMin(min);
|
||||
this.parseMax(max);
|
||||
this.parseRandBound();
|
||||
},
|
||||
parseMin(min) {
|
||||
if (typeof min !== 'number') {
|
||||
throw TypeError('Type of millis_min must be a number');
|
||||
}
|
||||
this.min = min;
|
||||
},
|
||||
parseMax(max) {
|
||||
if (typeof max === 'number') {
|
||||
this.max = max;
|
||||
} else if (typeof max === 'string') {
|
||||
let matched = max.match(this.rex_num);
|
||||
if (matched === null) {
|
||||
throw TypeError('String millis_max must have a number contained');
|
||||
}
|
||||
let delta = Number(matched[0]);
|
||||
this.max = this.min + delta;
|
||||
this.min = this.min - delta;
|
||||
} else {
|
||||
this.max = this.min;
|
||||
}
|
||||
},
|
||||
parseRandBound() {
|
||||
this.rand_bound = Math.ceil(Math.random() * (this.max - this.min));
|
||||
},
|
||||
};
|
||||
|
||||
function compare(a, b){
|
||||
return a > b ? 1 :
|
||||
a < b ? -1:
|
||||
0;
|
||||
}
|
||||
|
||||
function parseVersion(v){
|
||||
var m = /(\d+)\.(\d+)\.(\d+)[ ]?(Alpha|Beta)?(\d*)/.exec(v);
|
||||
if(!m){
|
||||
throw new Error("版本格式不合法: " + v);
|
||||
}
|
||||
return {
|
||||
major: parseInt(m[1]),
|
||||
minor: parseInt(m[2]),
|
||||
revision: parseInt(m[3]),
|
||||
buildType: buildType(m[4]),
|
||||
build: m[5] ? parseInt(m[5]) : 1
|
||||
};
|
||||
}
|
||||
|
||||
function buildType(str){
|
||||
if(str == 'Alpha'){
|
||||
return buildTypes.alpha;
|
||||
}
|
||||
if(str == 'Beta'){
|
||||
return buildTypes.beta;
|
||||
}
|
||||
return buildTypes.release;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
(function $LazY() {
|
||||
return this.sleep = $.sleep.bind($);
|
||||
}).call(this, millis_min, millis_max);
|
||||
},
|
||||
isStopped() {
|
||||
return runtime.isStopped();
|
||||
},
|
||||
notStopped() {
|
||||
return !this.isStopped();
|
||||
},
|
||||
isRunning() {
|
||||
return this.notStopped();
|
||||
},
|
||||
exit() {
|
||||
return runtime.exit.apply(runtime, arguments);
|
||||
},
|
||||
stop() {
|
||||
this.exit();
|
||||
},
|
||||
setClip(text) {
|
||||
return runtime.setClip(text);
|
||||
},
|
||||
getClip() {
|
||||
return runtime.getClip();
|
||||
},
|
||||
currentPackage() {
|
||||
this.auto();
|
||||
return runtime.info.getLatestPackage();
|
||||
},
|
||||
currentActivity() {
|
||||
this.auto();
|
||||
return runtime.info.getLatestActivity();
|
||||
},
|
||||
waitForActivity(activity, period) {
|
||||
_.ensureNonUiThread();
|
||||
period = period || 200;
|
||||
while (this.currentActivity() !== activity) {
|
||||
sleep(period);
|
||||
}
|
||||
},
|
||||
waitForPackage(packageName, period) {
|
||||
_.ensureNonUiThread();
|
||||
period = period || 200;
|
||||
while (this.currentPackage() !== packageName) {
|
||||
sleep(period);
|
||||
}
|
||||
},
|
||||
random(min, max) {
|
||||
if (arguments.length === 0) {
|
||||
return Math.random();
|
||||
}
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
},
|
||||
setScreenMetrics() {
|
||||
return runtime.setScreenMetrics.apply(runtime, arguments);
|
||||
},
|
||||
requiresApi() {
|
||||
return runtime.requiresApi.apply(runtime, arguments);
|
||||
},
|
||||
requiresAutojsVersion(version) {
|
||||
if (typeof version === 'number') {
|
||||
if (_.compare(version, app.autojs.versionCode) > 0) {
|
||||
throw new Error('需要Auto.js版本号' + version + '以上才能运行');
|
||||
}
|
||||
} else {
|
||||
if (_.compareVersion(version, app.autojs.versionName) > 0) {
|
||||
throw new Error('需要Auto.js版本' + version + '以上才能运行');
|
||||
}
|
||||
}
|
||||
},
|
||||
isPlainObject(o) {
|
||||
return Object.prototype.toString.call(o).slice(8, -1) === 'Object';
|
||||
},
|
||||
isInteger(o) {
|
||||
return Number.isInteger(o);
|
||||
},
|
||||
isNullish(o) {
|
||||
// nullish coalescing operator: ??
|
||||
return o === null || o === undefined;
|
||||
},
|
||||
isPrimitive(o) {
|
||||
return o !== Object(o);
|
||||
},
|
||||
isReference(o) {
|
||||
return o === Object(o);
|
||||
},
|
||||
});
|
||||
};
|
||||
29
autojs/src/main/assets/modules/custom-polyfill.js
Normal file
29
autojs/src/main/assets/modules/custom-polyfill.js
Normal file
@@ -0,0 +1,29 @@
|
||||
module.exports = {
|
||||
fill() {
|
||||
if (!Object.getOwnPropertyDescriptors) {
|
||||
/**
|
||||
* @param {Object} o
|
||||
* @return {Object.<string,PropertyDescriptor>} <!-- or {PropertyDescriptorMap} -->
|
||||
*/
|
||||
Object.getOwnPropertyDescriptors = function (o) {
|
||||
let _descriptor = {};
|
||||
Object.getOwnPropertyNames(o).forEach((k) => {
|
||||
_descriptor[k] = Object.getOwnPropertyDescriptor(o, k);
|
||||
});
|
||||
return _descriptor;
|
||||
};
|
||||
}
|
||||
|
||||
if (!Array.prototype.flat) {
|
||||
Object.defineProperty(Array.prototype, 'flat', {
|
||||
value(depth) {
|
||||
return (function _flat(arr, d) {
|
||||
return d <= 0 ? arr : arr.reduce((a, b) => {
|
||||
return a.concat(Array.isArray(b) ? _flat(b, d - 1) : b);
|
||||
}, []);
|
||||
})(this.slice(), depth || 1);
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -35,41 +35,39 @@ public class Loopers implements MessageQueue.IdleHandler {
|
||||
private static final Runnable EMPTY_RUNNABLE = () -> {
|
||||
};
|
||||
|
||||
private volatile ThreadLocal<Boolean> waitWhenIdle = new ThreadLocal<Boolean>() {
|
||||
private final ThreadLocal<Boolean> waitWhenIdle = new ThreadLocal<>() {
|
||||
@Nullable
|
||||
@Override
|
||||
protected Boolean initialValue() {
|
||||
return Looper.myLooper() == Looper.getMainLooper();
|
||||
}
|
||||
};
|
||||
private volatile ThreadLocal<HashSet<Integer>> waitIds = new ThreadLocal<HashSet<Integer>>() {
|
||||
private final ThreadLocal<HashSet<Integer>> waitIds = new ThreadLocal<>() {
|
||||
@Nullable
|
||||
@Override
|
||||
protected HashSet<Integer> initialValue() {
|
||||
return new HashSet<>();
|
||||
}
|
||||
};
|
||||
private volatile ThreadLocal<Integer> maxWaitId = new ThreadLocal<Integer>() {
|
||||
private final ThreadLocal<Integer> maxWaitId = new ThreadLocal<>() {
|
||||
@Nullable
|
||||
@Override
|
||||
protected Integer initialValue() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
private volatile ThreadLocal<CopyOnWriteArrayList<LooperQuitHandler>> looperQuitHandlers = new ThreadLocal<>();
|
||||
private final ThreadLocal<CopyOnWriteArrayList<LooperQuitHandler>> looperQuitHandlers = new ThreadLocal<>();
|
||||
private volatile Looper mServantLooper;
|
||||
private Timers mTimers;
|
||||
private ScriptRuntime mScriptRuntime;
|
||||
private final Timers mTimers;
|
||||
private LooperQuitHandler mMainLooperQuitHandler;
|
||||
private Handler mMainHandler;
|
||||
private Looper mMainLooper;
|
||||
private Threads mThreads;
|
||||
private MessageQueue mMainMessageQueue;
|
||||
private final Handler mMainHandler;
|
||||
private final Looper mMainLooper;
|
||||
private final Threads mThreads;
|
||||
private final MessageQueue mMainMessageQueue;
|
||||
|
||||
public Loopers(ScriptRuntime runtime) {
|
||||
mTimers = runtime.timers;
|
||||
mThreads = runtime.threads;
|
||||
mScriptRuntime = runtime;
|
||||
prepare();
|
||||
mMainLooper = Looper.myLooper();
|
||||
mMainHandler = new Handler();
|
||||
@@ -122,9 +120,9 @@ public class Loopers implements MessageQueue.IdleHandler {
|
||||
|
||||
|
||||
private void initServantThread() {
|
||||
final Object lock = Loopers.this;
|
||||
new ThreadCompat(() -> {
|
||||
Looper.prepare();
|
||||
final Object lock = Loopers.this;
|
||||
mServantLooper = Looper.myLooper();
|
||||
synchronized (lock) {
|
||||
lock.notifyAll();
|
||||
|
||||
@@ -14,12 +14,10 @@ import com.stardust.concurrent.VolatileBox;
|
||||
|
||||
public class Timer {
|
||||
|
||||
private static final String LOG_TAG = "Timer";
|
||||
|
||||
private SparseArray<Runnable> mHandlerCallbacks = new SparseArray<>();
|
||||
private final SparseArray<Runnable> mHandlerCallbacks = new SparseArray<>();
|
||||
private int mCallbackMaxId = 0;
|
||||
private ScriptRuntime mRuntime;
|
||||
private Handler mHandler;
|
||||
private final ScriptRuntime mRuntime;
|
||||
private final Handler mHandler;
|
||||
private long mMaxCallbackUptimeMillis = 0;
|
||||
private final VolatileBox<Long> mMaxCallbackMillisForAllThread;
|
||||
|
||||
@@ -39,7 +37,7 @@ public class Timer {
|
||||
mCallbackMaxId++;
|
||||
final int id = mCallbackMaxId;
|
||||
Runnable r = () -> {
|
||||
callFunction(callback, null, args);
|
||||
callFunction(callback, args);
|
||||
mHandlerCallbacks.remove(id);
|
||||
};
|
||||
mHandlerCallbacks.put(id, r);
|
||||
@@ -47,15 +45,15 @@ public class Timer {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void callFunction(Object callback, Object thiz, Object[] args) {
|
||||
private void callFunction(Object callback, Object[] args) {
|
||||
if(Looper.myLooper() == Looper.getMainLooper()){
|
||||
try {
|
||||
mRuntime.bridges.callFunction(callback, thiz, args);
|
||||
mRuntime.bridges.callFunction(callback, null, args);
|
||||
}catch (Exception e){
|
||||
mRuntime.exit(e);
|
||||
}
|
||||
}else {
|
||||
mRuntime.bridges.callFunction(callback, thiz, args);
|
||||
mRuntime.bridges.callFunction(callback, null, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +69,7 @@ public class Timer {
|
||||
public void run() {
|
||||
if (mHandlerCallbacks.get(id) == null)
|
||||
return;
|
||||
callFunction(listener, null, args);
|
||||
callFunction(listener, args);
|
||||
postDelayed(this, interval);
|
||||
}
|
||||
};
|
||||
@@ -89,9 +87,6 @@ public class Timer {
|
||||
}
|
||||
}
|
||||
|
||||
public void post(Runnable r) {
|
||||
|
||||
}
|
||||
|
||||
public boolean clearInterval(int id) {
|
||||
return clearCallback(id);
|
||||
@@ -101,7 +96,7 @@ public class Timer {
|
||||
mCallbackMaxId++;
|
||||
final int id = mCallbackMaxId;
|
||||
Runnable r = () -> {
|
||||
callFunction(listener, null, args);
|
||||
callFunction(listener, args);
|
||||
mHandlerCallbacks.remove(id);
|
||||
};
|
||||
mHandlerCallbacks.put(id, r);
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.stardust.autojs.core.looper;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.stardust.autojs.engine.RhinoJavaScriptEngine;
|
||||
import com.stardust.autojs.runtime.ScriptRuntime;
|
||||
@@ -18,12 +19,12 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class TimerThread extends ThreadCompat {
|
||||
|
||||
private static ConcurrentHashMap<Thread, Timer> sTimerMap = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentHashMap<Thread, Timer> sTimerMap = new ConcurrentHashMap<>();
|
||||
|
||||
private Timer mTimer;
|
||||
private final VolatileBox<Long> mMaxCallbackUptimeMillisForAllThreads;
|
||||
private final ScriptRuntime mRuntime;
|
||||
private Runnable mTarget;
|
||||
private final Runnable mTarget;
|
||||
private boolean mRunning = false;
|
||||
private final Object mRunningLock = new Object();
|
||||
|
||||
@@ -46,7 +47,7 @@ public class TimerThread extends ThreadCompat {
|
||||
Looper.loop();
|
||||
} catch (Throwable e) {
|
||||
if (!ScriptInterruptedException.causedByInterrupted(e)) {
|
||||
mRuntime.console.error(Thread.currentThread().toString() + ": ", e);
|
||||
mRuntime.console.error(Thread.currentThread() + ": ", e);
|
||||
}
|
||||
} finally {
|
||||
onExit();
|
||||
@@ -121,6 +122,7 @@ public class TimerThread extends ThreadCompat {
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Thread[" + getName() + "," + getPriority() + "]";
|
||||
|
||||
@@ -2,8 +2,9 @@ package com.stardust.autojs.core.ui.inflater.inflaters;
|
||||
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -135,31 +136,17 @@ public class BaseViewInflater<V extends View> implements ViewInflater<V> {
|
||||
case "width":
|
||||
case "layout_width":
|
||||
switch (value) {
|
||||
case "wrap_content":
|
||||
layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
break;
|
||||
case "fill_parent":
|
||||
case "match_parent":
|
||||
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
break;
|
||||
default:
|
||||
layoutParams.width = Dimensions.parseToPixel(value, view, parent, true);
|
||||
break;
|
||||
case "wrap_content" -> layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
case "fill_parent", "match_parent" -> layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
default -> layoutParams.width = Dimensions.parseToPixel(value, view, parent, true);
|
||||
}
|
||||
break;
|
||||
case "height":
|
||||
case "layout_height":
|
||||
switch (value) {
|
||||
case "wrap_content":
|
||||
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
break;
|
||||
case "fill_parent":
|
||||
case "match_parent":
|
||||
layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
break;
|
||||
default:
|
||||
layoutParams.height = Dimensions.parseToPixel(value, view, parent, false);
|
||||
break;
|
||||
case "wrap_content" -> layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
case "fill_parent", "match_parent" -> layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
default -> layoutParams.height = Dimensions.parseToPixel(value, view, parent, false);
|
||||
}
|
||||
break;
|
||||
case "layout_gravity":
|
||||
@@ -168,7 +155,7 @@ public class BaseViewInflater<V extends View> implements ViewInflater<V> {
|
||||
} else if (parent instanceof FrameLayout) {
|
||||
((FrameLayout.LayoutParams) layoutParams).gravity = Gravities.parse(value);
|
||||
} else {
|
||||
return setLayoutGravity(parent, view, Gravities.parse(value));
|
||||
return setLayoutGravity(view, Gravities.parse(value));
|
||||
}
|
||||
break;
|
||||
case "layout_weight":
|
||||
@@ -234,37 +221,30 @@ public class BaseViewInflater<V extends View> implements ViewInflater<V> {
|
||||
layoutRule = RelativeLayout.CENTER_IN_PARENT;
|
||||
break;
|
||||
case "layout_margin":
|
||||
if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
|
||||
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
|
||||
if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams params) {
|
||||
int margin = Dimensions.parseToIntPixel(value, view);
|
||||
params.bottomMargin = params.leftMargin = params.topMargin = params.rightMargin = margin;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
params.setMarginStart(margin);
|
||||
params.setMarginEnd(margin);
|
||||
}
|
||||
params.setMarginStart(margin);
|
||||
params.setMarginEnd(margin);
|
||||
}
|
||||
break;
|
||||
case "layout_marginLeft":
|
||||
if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
|
||||
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
|
||||
if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams params) {
|
||||
params.leftMargin = Dimensions.parseToIntPixel(value, view);
|
||||
}
|
||||
break;
|
||||
case "layout_marginTop":
|
||||
if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
|
||||
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
|
||||
if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams params) {
|
||||
params.topMargin = Dimensions.parseToIntPixel(value, view);
|
||||
}
|
||||
break;
|
||||
case "layout_marginRight":
|
||||
if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
|
||||
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
|
||||
if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams params) {
|
||||
params.rightMargin = Dimensions.parseToIntPixel(value, view);
|
||||
}
|
||||
break;
|
||||
case "layout_marginBottom":
|
||||
if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
|
||||
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
|
||||
if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams params) {
|
||||
params.bottomMargin = Dimensions.parseToIntPixel(value, view);
|
||||
}
|
||||
break;
|
||||
@@ -293,21 +273,13 @@ public class BaseViewInflater<V extends View> implements ViewInflater<V> {
|
||||
case "accessibilityTraversalBefore":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
case "alpha":
|
||||
view.setAlpha(Float.valueOf(value));
|
||||
break;
|
||||
case "autofillHints":
|
||||
case "autofilledHighlight":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
view.setAlpha(Float.parseFloat(value));
|
||||
break;
|
||||
case "backgroundTint":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setBackgroundTintList(ColorStateList.valueOf(Colors.parse(view, value)));
|
||||
}
|
||||
view.setBackgroundTintList(ColorStateList.valueOf(Colors.parse(view, value)));
|
||||
break;
|
||||
case "backgroundTintMode":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setBackgroundTintMode(TINT_MODES.get(value));
|
||||
}
|
||||
view.setBackgroundTintMode(TINT_MODES.get(value));
|
||||
break;
|
||||
case "checked":
|
||||
if (view instanceof CompoundButton) {
|
||||
@@ -315,106 +287,73 @@ public class BaseViewInflater<V extends View> implements ViewInflater<V> {
|
||||
}
|
||||
break;
|
||||
case "clickable":
|
||||
view.setClickable(Boolean.valueOf(value));
|
||||
view.setClickable(Boolean.parseBoolean(value));
|
||||
break;
|
||||
case "contentDescription":
|
||||
view.setContentDescription(Strings.parse(view, value));
|
||||
break;
|
||||
case "contextClickable":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
view.setContextClickable(Boolean.valueOf(value));
|
||||
}
|
||||
break;
|
||||
case "defaultFocusHighlightEnabled":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
view.setContextClickable(Boolean.parseBoolean(value));
|
||||
break;
|
||||
case "drawingCacheQuality":
|
||||
view.setDrawingCacheQuality(DRAWABLE_CACHE_QUALITIES.get(value));
|
||||
break;
|
||||
case "duplicateParentState":
|
||||
view.setDuplicateParentStateEnabled(Boolean.valueOf(value));
|
||||
view.setDuplicateParentStateEnabled(Boolean.parseBoolean(value));
|
||||
break;
|
||||
case "elevation":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setElevation(Dimensions.parseToIntPixel(value, view));
|
||||
}
|
||||
view.setElevation(Dimensions.parseToIntPixel(value, view));
|
||||
break;
|
||||
case "fadeScrollbars":
|
||||
view.setScrollbarFadingEnabled(Boolean.valueOf(value));
|
||||
view.setScrollbarFadingEnabled(Boolean.parseBoolean(value));
|
||||
break;
|
||||
case "fadingEdgeLength":
|
||||
view.setFadingEdgeLength(Dimensions.parseToIntPixel(value, view));
|
||||
break;
|
||||
case "filterTouchesWhenObscured":
|
||||
view.setFilterTouchesWhenObscured(Boolean.valueOf(value));
|
||||
view.setFilterTouchesWhenObscured(Boolean.parseBoolean(value));
|
||||
break;
|
||||
case "fitsSystemWindows":
|
||||
view.setFitsSystemWindows(Boolean.valueOf(value));
|
||||
view.setFitsSystemWindows(Boolean.parseBoolean(value));
|
||||
break;
|
||||
case "focusable":
|
||||
view.setFocusable(Boolean.valueOf(value));
|
||||
view.setFocusable(Boolean.parseBoolean(value));
|
||||
break;
|
||||
case "focusableInTouchMode":
|
||||
view.setFocusableInTouchMode(Boolean.valueOf(value));
|
||||
break;
|
||||
case "focusedByDefault":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
view.setFocusableInTouchMode(Boolean.parseBoolean(value));
|
||||
break;
|
||||
case "forceHasOverlappingRendering":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
view.forceHasOverlappingRendering(Boolean.valueOf(value));
|
||||
}
|
||||
view.forceHasOverlappingRendering(Boolean.parseBoolean(value));
|
||||
break;
|
||||
case "foreground":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
view.setForeground(getDrawables().parse(view, value));
|
||||
}
|
||||
view.setForeground(getDrawables().parse(view, value));
|
||||
break;
|
||||
case "foregroundGravity":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
view.setForegroundGravity(Gravities.parse(value));
|
||||
}
|
||||
view.setForegroundGravity(Gravities.parse(value));
|
||||
break;
|
||||
case "foregroundTint":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
view.setForegroundTintList(ColorStateList.valueOf(Colors.parse(view, value)));
|
||||
}
|
||||
view.setForegroundTintList(ColorStateList.valueOf(Colors.parse(view, value)));
|
||||
break;
|
||||
case "foregroundTintMode":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
view.setForegroundTintMode(TINT_MODES.get(value));
|
||||
}
|
||||
view.setForegroundTintMode(TINT_MODES.get(value));
|
||||
break;
|
||||
case "hapticFeedbackEnabled":
|
||||
view.setHapticFeedbackEnabled(Boolean.valueOf(value));
|
||||
view.setHapticFeedbackEnabled(Boolean.parseBoolean(value));
|
||||
break;
|
||||
case "importantForAccessibility":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
view.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY.get(value));
|
||||
}
|
||||
break;
|
||||
case "importantForAutofill":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
view.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY.get(value));
|
||||
break;
|
||||
case "isScrollContainer":
|
||||
view.setScrollContainer(Boolean.valueOf(value));
|
||||
view.setScrollContainer(Boolean.parseBoolean(value));
|
||||
break;
|
||||
case "keepScreenOn":
|
||||
view.setKeepScreenOn(Boolean.valueOf(value));
|
||||
break;
|
||||
case "keyboardNavigationCluster":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "layerType":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
view.setKeepScreenOn(Boolean.parseBoolean(value));
|
||||
break;
|
||||
case "layoutDirection":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
view.setLayoutDirection(LAYOUT_DIRECTIONS.get(value));
|
||||
}
|
||||
view.setLayoutDirection(LAYOUT_DIRECTIONS.get(value));
|
||||
break;
|
||||
case "longClickable":
|
||||
view.setLongClickable(Boolean.valueOf(value));
|
||||
view.setLongClickable(Boolean.parseBoolean(value));
|
||||
break;
|
||||
case "minHeight":
|
||||
view.setMinimumHeight(Dimensions.parseToIntPixel(value, view));
|
||||
@@ -422,48 +361,13 @@ public class BaseViewInflater<V extends View> implements ViewInflater<V> {
|
||||
case "minWidth":
|
||||
view.setMinimumWidth(Dimensions.parseToIntPixel(value, view));
|
||||
break;
|
||||
case "nextClusterForward":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "nextFocusDown":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "nextFocusForward":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "nextFocusLeft":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "nextFocusRight":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "nextFocusUp":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "onClick":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "paddingEnd":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
view.setPaddingRelative(view.getPaddingStart(), view.getPaddingTop(),
|
||||
Dimensions.parseToIntPixel(value, view), view.getPaddingBottom());
|
||||
} else {
|
||||
view.setPadding(view.getPaddingLeft(), view.getPaddingTop(),
|
||||
Dimensions.parseToIntPixel(value, view), view.getPaddingBottom());
|
||||
}
|
||||
break;
|
||||
case "paddingHorizontal":
|
||||
case "paddingVertical":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
view.setPaddingRelative(view.getPaddingStart(), view.getPaddingTop(),
|
||||
Dimensions.parseToIntPixel(value, view), view.getPaddingBottom());
|
||||
break;
|
||||
case "paddingStart":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
view.setPaddingRelative(Dimensions.parseToIntPixel(value, view), view.getPaddingTop(),
|
||||
view.getPaddingEnd(), view.getPaddingBottom());
|
||||
} else {
|
||||
view.setPadding(Dimensions.parseToIntPixel(value, view), view.getPaddingTop(),
|
||||
view.getPaddingRight(), view.getPaddingBottom());
|
||||
}
|
||||
view.setPaddingRelative(Dimensions.parseToIntPixel(value, view), view.getPaddingTop(),
|
||||
view.getPaddingEnd(), view.getPaddingBottom());
|
||||
break;
|
||||
case "requiresFadingEdge":
|
||||
for (String str : value.split("\\|")) {
|
||||
@@ -484,7 +388,7 @@ public class BaseViewInflater<V extends View> implements ViewInflater<V> {
|
||||
view.setRotationY(Float.parseFloat(value));
|
||||
break;
|
||||
case "saveEnabled":
|
||||
view.setSaveEnabled(Boolean.valueOf(value));
|
||||
view.setSaveEnabled(Boolean.parseBoolean(value));
|
||||
break;
|
||||
case "scaleX":
|
||||
view.setScaleX(Float.parseFloat(value));
|
||||
@@ -493,9 +397,7 @@ public class BaseViewInflater<V extends View> implements ViewInflater<V> {
|
||||
view.setScaleY(Float.parseFloat(value));
|
||||
break;
|
||||
case "scrollIndicators":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
view.setScrollIndicators(SCROLL_INDICATORS.get(value));
|
||||
}
|
||||
view.setScrollIndicators(SCROLL_INDICATORS.get(value));
|
||||
break;
|
||||
case "scrollX":
|
||||
view.setScrollX(Dimensions.parseToIntPixel(value, view));
|
||||
@@ -503,24 +405,14 @@ public class BaseViewInflater<V extends View> implements ViewInflater<V> {
|
||||
case "scrollY":
|
||||
view.setScrollY(Dimensions.parseToIntPixel(value, view));
|
||||
break;
|
||||
case "scrollbarAlwaysDrawHorizontalTrack":
|
||||
case "scrollbarAlwaysDrawVerticalTrack":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "scrollbarDefaultDelayBeforeFade":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
view.setScrollBarDefaultDelayBeforeFade(Integer.valueOf(value));
|
||||
}
|
||||
view.setScrollBarDefaultDelayBeforeFade(Integer.parseInt(value));
|
||||
break;
|
||||
case "scrollbarFadeDuration":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
view.setScrollBarFadeDuration(Integer.valueOf(value));
|
||||
}
|
||||
view.setScrollBarFadeDuration(Integer.parseInt(value));
|
||||
break;
|
||||
case "scrollbarSize":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
view.setScrollBarSize(Dimensions.parseToIntPixel(value, view));
|
||||
}
|
||||
view.setScrollBarSize(Dimensions.parseToIntPixel(value, view));
|
||||
break;
|
||||
case "scrollbarStyle":
|
||||
view.setScrollBarStyle(SCROLLBARS_STYLES.get(value));
|
||||
@@ -531,7 +423,7 @@ public class BaseViewInflater<V extends View> implements ViewInflater<V> {
|
||||
case "scrollbarTrackVertical":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
case "scrollbars":
|
||||
for (String str : value.split("|")) {
|
||||
for (String str : value.split("\\|")) {
|
||||
if (str.equals("horizontal")) {
|
||||
view.setHorizontalScrollBarEnabled(true);
|
||||
} else if (str.equals("vertical")) {
|
||||
@@ -540,7 +432,7 @@ public class BaseViewInflater<V extends View> implements ViewInflater<V> {
|
||||
}
|
||||
break;
|
||||
case "soundEffectsEnabled":
|
||||
view.setSoundEffectsEnabled(Boolean.valueOf(value));
|
||||
view.setSoundEffectsEnabled(Boolean.parseBoolean(value));
|
||||
break;
|
||||
case "stateListAnimator":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
@@ -548,21 +440,10 @@ public class BaseViewInflater<V extends View> implements ViewInflater<V> {
|
||||
view.setTag(Strings.parse(view, value));
|
||||
break;
|
||||
case "textAlignment":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
view.setTextAlignment(TEXT_ALIGNMENTS.get(value));
|
||||
}
|
||||
view.setTextAlignment(TEXT_ALIGNMENTS.get(value));
|
||||
break;
|
||||
case "textDirection":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
view.setTextDirection(TEXT_DIRECTIONS.get(value));
|
||||
}
|
||||
break;
|
||||
case "theme":
|
||||
//Exceptions.unsupports(view, attr, value);
|
||||
|
||||
break;
|
||||
case "tooltipText":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
view.setTextDirection(TEXT_DIRECTIONS.get(value));
|
||||
break;
|
||||
case "transformPivotX":
|
||||
view.setPivotX(Dimensions.parseToPixel(value, view));
|
||||
@@ -571,9 +452,7 @@ public class BaseViewInflater<V extends View> implements ViewInflater<V> {
|
||||
view.setPivotY(Dimensions.parseToPixel(value, view));
|
||||
break;
|
||||
case "transitionName":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setTransitionName(Strings.parse(view, value));
|
||||
}
|
||||
view.setTransitionName(Strings.parse(view, value));
|
||||
break;
|
||||
case "translationX":
|
||||
view.setTranslationX(Dimensions.parseToPixel(value, view));
|
||||
@@ -582,16 +461,34 @@ public class BaseViewInflater<V extends View> implements ViewInflater<V> {
|
||||
view.setTranslationY(Dimensions.parseToPixel(value, view));
|
||||
break;
|
||||
case "translationZ":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setTranslationZ(Dimensions.parseToPixel(value, view));
|
||||
}
|
||||
view.setTranslationZ(Dimensions.parseToPixel(value, view));
|
||||
break;
|
||||
case "visibility":
|
||||
view.setVisibility(VISIBILITY.get(value));
|
||||
break;
|
||||
case "autofillHints":
|
||||
case "autofilledHighlight":
|
||||
case "tooltipText":
|
||||
case "defaultFocusHighlightEnabled":
|
||||
case "focusedByDefault":
|
||||
case "importantForAutofill":
|
||||
case "keyboardNavigationCluster":
|
||||
case "layerType":
|
||||
case "nextClusterForward":
|
||||
case "nextFocusDown":
|
||||
case "nextFocusForward":
|
||||
case "nextFocusLeft":
|
||||
case "nextFocusRight":
|
||||
case "nextFocusUp":
|
||||
case "onClick":
|
||||
case "paddingHorizontal":
|
||||
case "paddingVertical":
|
||||
case "scrollbarAlwaysDrawHorizontalTrack":
|
||||
case "scrollbarAlwaysDrawVerticalTrack":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
|
||||
}
|
||||
if (layoutRule != null && parent instanceof RelativeLayout) {
|
||||
if (layoutTarget) {
|
||||
@@ -604,7 +501,7 @@ public class BaseViewInflater<V extends View> implements ViewInflater<V> {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean setLayoutGravity(ViewGroup parent, V view, int gravity) {
|
||||
public boolean setLayoutGravity(V view, int gravity) {
|
||||
try {
|
||||
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
|
||||
Field field = layoutParams.getClass().getField("gravity");
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.stardust.autojs.core.ui.inflater.inflaters;
|
||||
|
||||
import android.animation.LayoutTransition;
|
||||
import android.os.Build;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.stardust.autojs.core.ui.inflater.ResourceParser;
|
||||
@@ -39,22 +38,16 @@ public class ViewGroupInflater<V extends ViewGroup> extends BaseViewInflater<V>
|
||||
public boolean setAttr(V view, String attr, String value, ViewGroup parent, Map<String, String> attrs) {
|
||||
switch (attr) {
|
||||
case "addStatesFromChildren":
|
||||
view.setAddStatesFromChildren(Boolean.valueOf(value));
|
||||
break;
|
||||
case "alwaysDrawnWithCache":
|
||||
view.setAlwaysDrawnWithCacheEnabled(Boolean.valueOf(value));
|
||||
view.setAddStatesFromChildren(Boolean.parseBoolean(value));
|
||||
break;
|
||||
case "animateLayoutChanges":
|
||||
view.setLayoutTransition(new LayoutTransition());
|
||||
break;
|
||||
case "animationCache":
|
||||
view.setAnimationCacheEnabled(Boolean.valueOf(value));
|
||||
break;
|
||||
case "clipChildren":
|
||||
view.setClipChildren(Boolean.valueOf(value));
|
||||
view.setClipChildren(Boolean.parseBoolean(value));
|
||||
break;
|
||||
case "clipToPadding":
|
||||
view.setClipToPadding(Boolean.valueOf(value));
|
||||
view.setClipToPadding(Boolean.parseBoolean(value));
|
||||
break;
|
||||
case "descendantFocusability":
|
||||
view.setDescendantFocusability(DESCENDANT_FOCUSABILITY.get(value));
|
||||
@@ -63,15 +56,13 @@ public class ViewGroupInflater<V extends ViewGroup> extends BaseViewInflater<V>
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "layoutMode":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
view.setLayoutMode(LAYOUT_MODES.get(value));
|
||||
}
|
||||
view.setLayoutMode(LAYOUT_MODES.get(value));
|
||||
break;
|
||||
case "persistentDrawingCache":
|
||||
view.setPersistentDrawingCache(PERSISTENT_DRAWING_CACHE.get(value));
|
||||
break;
|
||||
case "splitMotionEvents":
|
||||
view.setMotionEventSplittingEnabled(Boolean.valueOf(value));
|
||||
view.setMotionEventSplittingEnabled(Boolean.parseBoolean(value));
|
||||
break;
|
||||
default:
|
||||
return super.setAttr(view, attr, value, parent, attrs);
|
||||
|
||||
@@ -9,11 +9,12 @@ import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.util.Base64;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
|
||||
import com.stardust.autojs.core.ui.inflater.ImageLoader;
|
||||
|
||||
import java.net.URL;
|
||||
@@ -41,7 +42,6 @@ public class Drawables {
|
||||
}
|
||||
|
||||
public Drawable parse(Context context, String value) {
|
||||
Resources resources = context.getResources();
|
||||
if (value.startsWith("@color/") || value.startsWith("@android:color/") || value.startsWith("#")) {
|
||||
return new ColorDrawable(Colors.parse(context, value));
|
||||
}
|
||||
@@ -49,30 +49,29 @@ public class Drawables {
|
||||
return loadAttrResources(context, value);
|
||||
}
|
||||
if (value.startsWith("file://")) {
|
||||
return decodeImage(value.substring(7));
|
||||
return decodeImage(context, value.substring(7));
|
||||
}
|
||||
return loadDrawableResources(context, value);
|
||||
}
|
||||
|
||||
public Drawable loadDrawableResources(Context context, String value) {
|
||||
int resId = context.getResources().getIdentifier(value, "drawable",
|
||||
context.getPackageName());
|
||||
if (resId == 0)
|
||||
int resId = context.getResources().getIdentifier(value, "drawable", context.getPackageName());
|
||||
if (resId == 0) {
|
||||
throw new Resources.NotFoundException("drawable not found: " + value);
|
||||
return context.getResources().getDrawable(resId);
|
||||
}
|
||||
return AppCompatResources.getDrawable(context, resId);
|
||||
}
|
||||
|
||||
public Drawable loadAttrResources(Context context, String value) {
|
||||
int[] attr = {context.getResources().getIdentifier(value.substring(1), "attr",
|
||||
context.getPackageName())};
|
||||
int[] attr = {context.getResources().getIdentifier(value.substring(1), "attr", context.getPackageName())};
|
||||
TypedArray ta = context.obtainStyledAttributes(attr);
|
||||
Drawable drawable = ta.getDrawable(0 /* index */);
|
||||
ta.recycle();
|
||||
return drawable;
|
||||
}
|
||||
|
||||
public Drawable decodeImage(String path) {
|
||||
return new BitmapDrawable(BitmapFactory.decodeFile(path));
|
||||
public Drawable decodeImage(Context context, String path) {
|
||||
return new BitmapDrawable(context.getResources(), BitmapFactory.decodeFile(path));
|
||||
}
|
||||
|
||||
public Drawable parse(View view, String name) {
|
||||
@@ -119,11 +118,7 @@ public class Drawables {
|
||||
if (value.startsWith("http://") || value.startsWith("https://")) {
|
||||
loadIntoBackground(view, Uri.parse(value));
|
||||
} else {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
view.setBackground(parse(view, value));
|
||||
} else {
|
||||
view.setBackgroundDrawable(parse(view, value));
|
||||
}
|
||||
view.setBackground(parse(view, value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,24 +7,23 @@ import android.graphics.Point;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.autojs.core.accessibility.AccessibilityBridge;
|
||||
import com.stardust.autojs.core.boardcast.BroadcastEmitter;
|
||||
import com.stardust.autojs.core.eventloop.EventEmitter;
|
||||
import com.stardust.autojs.core.looper.Loopers;
|
||||
import com.stardust.autojs.core.looper.MainThreadProxy;
|
||||
import com.stardust.autojs.core.looper.Timer;
|
||||
import com.stardust.autojs.runtime.ScriptRuntime;
|
||||
import com.stardust.notification.Notification;
|
||||
import com.stardust.notification.NotificationListenerService;
|
||||
import com.stardust.autojs.runtime.exception.ScriptException;
|
||||
import com.stardust.autojs.core.inputevent.InputEventObserver;
|
||||
import com.stardust.autojs.core.inputevent.TouchObserver;
|
||||
import com.stardust.autojs.core.looper.Loopers;
|
||||
import com.stardust.autojs.core.looper.Timer;
|
||||
import com.stardust.autojs.runtime.ScriptRuntime;
|
||||
import com.stardust.autojs.runtime.exception.ScriptException;
|
||||
import com.stardust.notification.Notification;
|
||||
import com.stardust.notification.NotificationListenerService;
|
||||
import com.stardust.util.MapBuilder;
|
||||
import com.stardust.view.accessibility.AccessibilityNotificationObserver;
|
||||
import com.stardust.view.accessibility.AccessibilityService;
|
||||
@@ -63,21 +62,20 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
|
||||
.put(AccessibilityService.GESTURE_SWIPE_DOWN_AND_RIGHT, "down_right")
|
||||
.build();
|
||||
|
||||
private AccessibilityBridge mAccessibilityBridge;
|
||||
private Context mContext;
|
||||
private final AccessibilityBridge mAccessibilityBridge;
|
||||
private final Context mContext;
|
||||
private TouchObserver mTouchObserver;
|
||||
private long mLastTouchEventMillis;
|
||||
private long mTouchEventTimeout = 10;
|
||||
private boolean mListeningKey = false;
|
||||
private Loopers mLoopers;
|
||||
private final Loopers mLoopers;
|
||||
private Handler mHandler;
|
||||
private boolean mListeningNotification = false;
|
||||
private boolean mListeningGesture = false;
|
||||
private boolean mListeningToast = false;
|
||||
private ScriptRuntime mScriptRuntime;
|
||||
private final ScriptRuntime mScriptRuntime;
|
||||
private volatile boolean mInterceptsAllKey = false;
|
||||
private KeyInterceptor mKeyInterceptor;
|
||||
private Set<String> mInterceptedKeys = new HashSet<>();
|
||||
private final Set<String> mInterceptedKeys = new HashSet<>();
|
||||
|
||||
public final BroadcastEmitter broadcast;
|
||||
|
||||
@@ -99,9 +97,6 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
|
||||
return new EventEmitter(mBridges, timer);
|
||||
}
|
||||
|
||||
public EventEmitter emitter(MainThreadProxy mainThreadProxy) {
|
||||
return new EventEmitter(mBridges, mScriptRuntime.timers.getMainTimer());
|
||||
}
|
||||
|
||||
public void observeKey() {
|
||||
if (mListeningKey)
|
||||
@@ -227,9 +222,7 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
|
||||
ensureHandler();
|
||||
mLoopers.waitWhenIdle(true);
|
||||
if (NotificationListenerService.Companion.getInstance() == null) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
||||
mContext.startActivity(new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS));
|
||||
}
|
||||
throw new ScriptException(mContext.getString(R.string.exception_notification_service_disabled));
|
||||
}
|
||||
NotificationListenerService.Companion.getInstance().addListener(this);
|
||||
@@ -245,20 +238,6 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
|
||||
mAccessibilityBridge.getNotificationObserver().addToastListener(this);
|
||||
}
|
||||
|
||||
public void observeGesture() {
|
||||
ScriptRuntime.requiresApi(Build.VERSION_CODES.O);
|
||||
if (mListeningGesture) {
|
||||
return;
|
||||
}
|
||||
AccessibilityService service = getAccessibilityService();
|
||||
if ((service.getServiceInfo().flags & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) == 0) {
|
||||
throw new ScriptException(mContext.getString(R.string.text_should_enable_gesture_observing));
|
||||
}
|
||||
service.getGestureEventDispatcher().addListener(this);
|
||||
ensureHandler();
|
||||
mLoopers.waitWhenIdle(true);
|
||||
mListeningGesture = true;
|
||||
}
|
||||
|
||||
public Events onNotification(Object listener) {
|
||||
on("notification", listener);
|
||||
@@ -286,8 +265,7 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
|
||||
if (mListeningNotification) {
|
||||
mAccessibilityBridge.getNotificationObserver().removeNotificationListener(this);
|
||||
mAccessibilityBridge.getNotificationObserver().removeToastListener(this);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2
|
||||
&& NotificationListenerService.Companion.getInstance() != null) {
|
||||
if (NotificationListenerService.Companion.getInstance() != null) {
|
||||
NotificationListenerService.Companion.getInstance().removeListener(this);
|
||||
}
|
||||
}
|
||||
@@ -298,16 +276,10 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
|
||||
}
|
||||
mKeyInterceptor = null;
|
||||
}
|
||||
if (mListeningGesture) {
|
||||
AccessibilityService service = mAccessibilityBridge.getService();
|
||||
if (service != null) {
|
||||
service.getGestureEventDispatcher().removeListener(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onKeyEvent(final int keyCode, final KeyEvent event) {
|
||||
public void onKeyEvent(final int keyCode, @NonNull final KeyEvent event) {
|
||||
mHandler.post(() -> {
|
||||
String keyName = KeyEvent.keyCodeToString(keyCode).substring(8).toLowerCase();
|
||||
emit(keyName, event);
|
||||
@@ -331,13 +303,13 @@ public class Events extends EventEmitter implements OnKeyListener, TouchObserver
|
||||
mHandler.post(() -> emit("touch", new Point(x, y)));
|
||||
}
|
||||
|
||||
public void onNotification(final Notification notification) {
|
||||
public void onNotification(@NonNull final Notification notification) {
|
||||
mHandler.post(() -> emit("notification", notification));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onToast(final AccessibilityNotificationObserver.Toast toast) {
|
||||
public void onToast(@NonNull final AccessibilityNotificationObserver.Toast toast) {
|
||||
mHandler.post(() -> emit("toast", toast));
|
||||
}
|
||||
|
||||
|
||||
@@ -55,13 +55,13 @@ public class Images {
|
||||
|
||||
private static final String TAG = Images.class.getSimpleName();
|
||||
|
||||
private ScriptRuntime mScriptRuntime;
|
||||
private ScreenCaptureRequester mScreenCaptureRequester;
|
||||
private final ScriptRuntime mScriptRuntime;
|
||||
private final ScreenCaptureRequester mScreenCaptureRequester;
|
||||
private ScreenCapturer mScreenCapturer;
|
||||
private Context mContext;
|
||||
private final Context mContext;
|
||||
private Image mPreCapture;
|
||||
private ImageWrapper mPreCaptureImage;
|
||||
private ScreenMetrics mScreenMetrics;
|
||||
private final ScreenMetrics mScreenMetrics;
|
||||
private volatile boolean mOpenCvInitialized = false;
|
||||
|
||||
@ScriptVariable
|
||||
@@ -169,11 +169,11 @@ public class Images {
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
Paint paint = new Paint();
|
||||
if (direction == Gravity.LEFT || direction == Gravity.RIGHT) {
|
||||
canvas.drawBitmap(img1.getBitmap(), 0, (height - img1.getHeight()) / 2, paint);
|
||||
canvas.drawBitmap(img2.getBitmap(), img1.getWidth(), (height - img2.getHeight()) / 2, paint);
|
||||
canvas.drawBitmap(img1.getBitmap(), 0, (float) (height - img1.getHeight()) / 2, paint);
|
||||
canvas.drawBitmap(img2.getBitmap(), img1.getWidth(), (float) (height - img2.getHeight()) / 2, paint);
|
||||
} else {
|
||||
canvas.drawBitmap(img1.getBitmap(), (width - img1.getWidth()) / 2, 0, paint);
|
||||
canvas.drawBitmap(img2.getBitmap(), (width - img2.getWidth()) / 2, img1.getHeight(), paint);
|
||||
canvas.drawBitmap(img1.getBitmap(), (float) (width - img1.getWidth()) / 2, 0, paint);
|
||||
canvas.drawBitmap(img2.getBitmap(), (float) (width - img2.getWidth()) / 2, img1.getHeight(), paint);
|
||||
}
|
||||
return ImageWrapper.ofBitmap(bitmap);
|
||||
}
|
||||
@@ -217,16 +217,12 @@ public class Images {
|
||||
}
|
||||
|
||||
private Bitmap.CompressFormat parseImageFormat(String format) {
|
||||
switch (format) {
|
||||
case "png":
|
||||
return Bitmap.CompressFormat.PNG;
|
||||
case "jpeg":
|
||||
case "jpg":
|
||||
return Bitmap.CompressFormat.JPEG;
|
||||
case "webp":
|
||||
return Bitmap.CompressFormat.WEBP;
|
||||
}
|
||||
return null;
|
||||
return switch (format) {
|
||||
case "png" -> Bitmap.CompressFormat.PNG;
|
||||
case "jpeg", "jpg" -> Bitmap.CompressFormat.JPEG;
|
||||
case "webp" -> Bitmap.CompressFormat.WEBP;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
public ImageWrapper load(String src) {
|
||||
@@ -265,7 +261,7 @@ public class Images {
|
||||
}
|
||||
|
||||
public void releaseScreenCapturer() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mScreenCapturer != null) {
|
||||
if (mScreenCapturer != null) {
|
||||
mScreenCapturer.release();
|
||||
}
|
||||
}
|
||||
@@ -367,4 +363,4 @@ public class Images {
|
||||
mOpenCvInitialized = true;
|
||||
Log.i(TAG, "opencv: initialized");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.stardust.autojs.core.eventloop.EventEmitter;
|
||||
@@ -24,7 +25,6 @@ import java.util.Set;
|
||||
|
||||
public class Sensors extends EventEmitter implements Loopers.LooperQuitHandler {
|
||||
|
||||
|
||||
public class SensorEventEmitter extends EventEmitter implements SensorEventListener {
|
||||
|
||||
public SensorEventEmitter(ScriptBridges bridges) {
|
||||
@@ -58,25 +58,22 @@ public class Sensors extends EventEmitter implements Loopers.LooperQuitHandler {
|
||||
public static final int fastest = SensorManager.SENSOR_DELAY_FASTEST;
|
||||
}
|
||||
|
||||
|
||||
private static final Map<String, Integer> SENSORS = new MapBuilder<String, Integer>()
|
||||
.put("ACCELEROMETER", Sensor.TYPE_ACCELEROMETER)
|
||||
.put("MAGNETIC_FIELD", Sensor.TYPE_MAGNETIC_FIELD)
|
||||
.put("ORIENTATION", Sensor.TYPE_ORIENTATION)
|
||||
.put("AMBIENT_TEMPERATURE", Sensor.TYPE_AMBIENT_TEMPERATURE)
|
||||
.put("GRAVITY", Sensor.TYPE_GRAVITY)
|
||||
.put("GYROSCOPE", Sensor.TYPE_GYROSCOPE)
|
||||
.put("LIGHT", Sensor.TYPE_LIGHT)
|
||||
.put("TEMPERATURE", Sensor.TYPE_TEMPERATURE)
|
||||
.put("PRESSURE", Sensor.TYPE_PRESSURE)
|
||||
.put("AMBIENT_TEMPERATURE", Sensor.TYPE_AMBIENT_TEMPERATURE)
|
||||
.put("PROXIMITY", Sensor.TYPE_PROXIMITY)
|
||||
.put("GRAVITY", Sensor.TYPE_GRAVITY)
|
||||
.put("LINEAR_ACCELERATION", Sensor.TYPE_LINEAR_ACCELERATION)
|
||||
.put("MAGNETIC_FIELD", Sensor.TYPE_MAGNETIC_FIELD)
|
||||
.put("ORIENTATION", Sensor.TYPE_ORIENTATION)
|
||||
.put("PRESSURE", Sensor.TYPE_PRESSURE)
|
||||
.put("PROXIMITY", Sensor.TYPE_PROXIMITY)
|
||||
.put("RELATIVE_HUMIDITY", Sensor.TYPE_RELATIVE_HUMIDITY)
|
||||
.put("AMBIENT_TEMPERATURE", Sensor.TYPE_AMBIENT_TEMPERATURE)
|
||||
.put("TEMPERATURE", Sensor.TYPE_AMBIENT_TEMPERATURE)
|
||||
.build();
|
||||
|
||||
public boolean ignoresUnsupportedSensor = false;
|
||||
public final Delay delay = new Delay();
|
||||
|
||||
private final Set<SensorEventEmitter> mSensorEventEmitters = new HashSet<>();
|
||||
private final SensorManager mSensorManager;
|
||||
@@ -84,7 +81,6 @@ public class Sensors extends EventEmitter implements Loopers.LooperQuitHandler {
|
||||
private final SensorEventEmitter mNoOpSensorEventEmitter;
|
||||
private final ScriptRuntime mScriptRuntime;
|
||||
|
||||
|
||||
public Sensors(Context context, ScriptRuntime runtime) {
|
||||
super(runtime.bridges);
|
||||
mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
|
||||
@@ -99,8 +95,9 @@ public class Sensors extends EventEmitter implements Loopers.LooperQuitHandler {
|
||||
}
|
||||
|
||||
public SensorEventEmitter register(String sensorName, int delay) {
|
||||
if (sensorName == null)
|
||||
if (sensorName == null) {
|
||||
throw new NullPointerException("sensorName = null");
|
||||
}
|
||||
Sensor sensor = getSensor(sensorName);
|
||||
if (sensor == null) {
|
||||
if (ignoresUnsupportedSensor) {
|
||||
@@ -122,26 +119,19 @@ public class Sensors extends EventEmitter implements Loopers.LooperQuitHandler {
|
||||
return emitter;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean shouldQuit() {
|
||||
if (mSensorEventEmitters.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return mSensorEventEmitters.isEmpty();
|
||||
}
|
||||
|
||||
public Sensor getSensor(String sensorName) {
|
||||
Integer type = SENSORS.get(sensorName.toUpperCase());
|
||||
if (type == null)
|
||||
type = getSensorTypeByReflect(sensorName);
|
||||
if (type == null)
|
||||
return null;
|
||||
return mSensorManager.getDefaultSensor(type);
|
||||
sensorName = sensorName.toUpperCase();
|
||||
Integer type = SENSORS.get(sensorName);
|
||||
type = type == null ? getSensorTypeByReflect(sensorName) : type;
|
||||
return type == null ? null : mSensorManager.getDefaultSensor(type);
|
||||
}
|
||||
|
||||
private Integer getSensorTypeByReflect(String sensorName) {
|
||||
sensorName = sensorName.toUpperCase();
|
||||
try {
|
||||
Field field = Sensor.class.getField("TYPE_" + sensorName);
|
||||
return (Integer) field.get(null);
|
||||
@@ -151,12 +141,12 @@ public class Sensors extends EventEmitter implements Loopers.LooperQuitHandler {
|
||||
}
|
||||
|
||||
public void unregister(SensorEventEmitter emitter) {
|
||||
if (emitter == null)
|
||||
return;
|
||||
synchronized (mSensorEventEmitters) {
|
||||
mSensorEventEmitters.remove(emitter);
|
||||
if (emitter != null) {
|
||||
synchronized (mSensorEventEmitters) {
|
||||
mSensorEventEmitters.remove(emitter);
|
||||
}
|
||||
mSensorManager.unregisterListener(emitter);
|
||||
}
|
||||
mSensorManager.unregisterListener(emitter);
|
||||
}
|
||||
|
||||
public void unregisterAll() {
|
||||
|
||||
@@ -110,8 +110,8 @@ public class UI extends ProxyObject {
|
||||
private class Drawables extends com.stardust.autojs.core.ui.inflater.util.Drawables {
|
||||
|
||||
@Override
|
||||
public Drawable decodeImage(String path) {
|
||||
return super.decodeImage(mRuntime.files.path(path));
|
||||
public Drawable decodeImage(Context context, String path) {
|
||||
return super.decodeImage(context, mRuntime.files.path(path));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.stardust">
|
||||
|
||||
package="com.stardust"
|
||||
>
|
||||
|
||||
<application android:allowBackup="true"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
>
|
||||
|
||||
</application>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true" />
|
||||
</manifest>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.stardust.app;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
@@ -9,6 +10,8 @@ import android.os.Looper;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import kotlin.Suppress;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/8/4.
|
||||
*/
|
||||
@@ -20,24 +23,17 @@ public class DialogUtils {
|
||||
|
||||
if (!isActivityContext(context)) {
|
||||
Window window = dialog.getWindow();
|
||||
int type;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||
} else {
|
||||
type = WindowManager.LayoutParams.TYPE_PHONE;
|
||||
}
|
||||
if (window != null)
|
||||
int type = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
||||
? WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
|
||||
: WindowManager.LayoutParams.TYPE_PHONE;
|
||||
if (window != null) {
|
||||
window.setType(type);
|
||||
}
|
||||
}
|
||||
if (Looper.getMainLooper() == Looper.myLooper()) {
|
||||
dialog.show();
|
||||
} else {
|
||||
GlobalAppContext.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
dialog.show();
|
||||
}
|
||||
});
|
||||
GlobalAppContext.post(dialog::show);
|
||||
}
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@@ -23,21 +23,19 @@ import java.util.Objects;
|
||||
* Created by Stardust on 2017/4/1.
|
||||
*/
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
public class PFiles {
|
||||
|
||||
static final int DEFAULT_BUFFER_SIZE = 8192;
|
||||
static final String DEFAULT_ENCODING = Charset.defaultCharset().name();
|
||||
|
||||
public static PFileInterface open(String path, String mode, String encoding, int bufferSize) {
|
||||
switch (mode) {
|
||||
case "r":
|
||||
return new PReadableTextFile(path, encoding, bufferSize);
|
||||
case "w":
|
||||
return new PWritableTextFile(path, encoding, bufferSize, false);
|
||||
case "a":
|
||||
return new PWritableTextFile(path, encoding, bufferSize, true);
|
||||
}
|
||||
return null;
|
||||
return switch (mode) {
|
||||
case "r" -> new PReadableTextFile(path, encoding, bufferSize);
|
||||
case "w" -> new PWritableTextFile(path, encoding, bufferSize, false);
|
||||
case "a" -> new PWritableTextFile(path, encoding, bufferSize, true);
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
public static Object open(String path, String mode, String encoding) {
|
||||
|
||||
@@ -107,16 +107,14 @@ public final class ResourceMonitor {
|
||||
if (sHandler == null) {
|
||||
sHandler = new Handler(Looper.getMainLooper());
|
||||
}
|
||||
sHandler.post(new Runnable() {
|
||||
public final void run() {
|
||||
UnclosedResourceDetectedException detectedException = new UnclosedResourceDetectedException(exception);
|
||||
detectedException.fillInStackTrace();
|
||||
Log.w(LOG_TAG, "UnclosedResourceDetected", detectedException);
|
||||
if (sUnclosedResourceDetectedHandler != null) {
|
||||
sUnclosedResourceDetectedHandler.onUnclosedResourceDetected(detectedException);
|
||||
} else {
|
||||
throw detectedException;
|
||||
}
|
||||
sHandler.post(() -> {
|
||||
UnclosedResourceDetectedException detectedException = new UnclosedResourceDetectedException(exception);
|
||||
detectedException.fillInStackTrace();
|
||||
Log.w(LOG_TAG, "UnclosedResourceDetected", detectedException);
|
||||
if (sUnclosedResourceDetectedHandler != null) {
|
||||
sUnclosedResourceDetectedHandler.onUnclosedResourceDetected(detectedException);
|
||||
} else {
|
||||
throw detectedException;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.stardust.auojs.inrt.launch.GlobalProjectLauncher
|
||||
import java.util.ArrayList
|
||||
|
||||
import android.content.pm.PackageManager.PERMISSION_DENIED
|
||||
import android.os.Looper
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2018/2/2.
|
||||
@@ -34,7 +35,7 @@ class SplashActivity : AppCompatActivity() {
|
||||
if (!Pref.isFirstUsing) {
|
||||
main()
|
||||
} else {
|
||||
Handler().postDelayed({ this@SplashActivity.main() }, INIT_TIMEOUT)
|
||||
Handler(Looper.myLooper()!!).postDelayed({ this@SplashActivity.main() }, INIT_TIMEOUT)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user