add: promise support; fix: dialogs and setClip ANR on ui thread;
This commit is contained in:
@@ -164,8 +164,8 @@ public class RootAutomator {
|
||||
|
||||
public void touchUp(int id) throws IOException {
|
||||
sendEvent(EV_ABS, ABS_MT_TRACKING_ID, id);
|
||||
// sendEvent(EV_KEY, BTN_TOUCH, 0x00000000);
|
||||
// sendEvent(EV_KEY, BTN_TOOL_FINGER, 0x00000000);
|
||||
sendEvent(EV_KEY, BTN_TOUCH, 0x00000000);
|
||||
sendEvent(EV_KEY, BTN_TOOL_FINGER, 0x00000000);
|
||||
sendEvent(EV_SYN, SYN_REPORT, 0x00000000);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@ package com.stardust.autojs.core.ui;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.DialogInterface;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.os.Looper;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
@@ -12,9 +11,14 @@ import android.view.WindowManager;
|
||||
import com.afollestad.materialdialogs.DialogAction;
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.afollestad.materialdialogs.Theme;
|
||||
import com.stardust.concurrent.VolatileBox;
|
||||
import com.stardust.autojs.runtime.ScriptBridges;
|
||||
import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
|
||||
import com.stardust.concurrent.VolatileDispose;
|
||||
import com.stardust.util.ArrayUtils;
|
||||
import com.stardust.util.UiHandler;
|
||||
|
||||
import org.jdeferred.impl.DeferredObject;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/5/8.
|
||||
*/
|
||||
@@ -48,98 +52,121 @@ public class BlockedMaterialDialog extends MaterialDialog {
|
||||
|
||||
public static class Builder extends MaterialDialog.Builder {
|
||||
|
||||
private VolatileDispose<Object> mResultBox;
|
||||
private UiHandler mUiHandler;
|
||||
private Object mCallback;
|
||||
private ScriptBridges mScriptBridges;
|
||||
private boolean mNotified = false;
|
||||
|
||||
public Builder(Context context, UiHandler uiHandler) {
|
||||
public Builder(Context context, UiHandler uiHandler, ScriptBridges scriptBridges, Object callback) {
|
||||
super(context);
|
||||
super.theme(Theme.LIGHT);
|
||||
mUiHandler = uiHandler;
|
||||
mScriptBridges = scriptBridges;
|
||||
mCallback = callback;
|
||||
if (Looper.getMainLooper() != Looper.myLooper()) {
|
||||
mResultBox = new VolatileDispose<>();
|
||||
}
|
||||
}
|
||||
|
||||
public MaterialDialog.Builder input(@Nullable CharSequence hint, @Nullable CharSequence prefill, boolean allowEmptyInput, final VolatileBox<String> result) {
|
||||
dismissListener(result);
|
||||
super.input(hint, prefill, allowEmptyInput, new MaterialDialog.InputCallback() {
|
||||
@Override
|
||||
public void onInput(@NonNull MaterialDialog dialog, CharSequence input) {
|
||||
result.set(input.toString());
|
||||
synchronized (result) {
|
||||
result.notify();
|
||||
}
|
||||
public MaterialDialog.Builder input(@Nullable CharSequence hint, @Nullable CharSequence prefill, boolean allowEmptyInput) {
|
||||
super.input(hint, prefill, allowEmptyInput, (dialog, input) -> setAndNotify(input.toString()));
|
||||
return this;
|
||||
}
|
||||
|
||||
private void setAndNotify(Object r) {
|
||||
if (mNotified) {
|
||||
return;
|
||||
}
|
||||
mNotified = true;
|
||||
if (mCallback != null) {
|
||||
mScriptBridges.callFunction(mCallback, null, new Object[]{r});
|
||||
}
|
||||
if (mResultBox != null) {
|
||||
mResultBox.setAndNotify(r);
|
||||
}
|
||||
}
|
||||
|
||||
private void setAndNotify(int r) {
|
||||
if (mNotified) {
|
||||
return;
|
||||
}
|
||||
mNotified = true;
|
||||
if (mCallback != null) {
|
||||
mScriptBridges.callFunction(mCallback, null, new int[]{r});
|
||||
}
|
||||
if (mResultBox != null) {
|
||||
mResultBox.setAndNotify(r);
|
||||
}
|
||||
}
|
||||
|
||||
private void setAndNotify(boolean r) {
|
||||
if (mNotified) {
|
||||
return;
|
||||
}
|
||||
mNotified = true;
|
||||
if (mCallback != null) {
|
||||
mScriptBridges.callFunction(mCallback, null, new boolean[]{r});
|
||||
}
|
||||
if (mResultBox != null) {
|
||||
mResultBox.setAndNotify(r);
|
||||
}
|
||||
}
|
||||
|
||||
public Builder alert() {
|
||||
dismissListener(dialog -> setAndNotify(null));
|
||||
onAny((dialog, which) -> setAndNotify(null));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder confirm() {
|
||||
dismissListener(dialog -> setAndNotify(false));
|
||||
onAny((dialog, which) -> {
|
||||
if (which == DialogAction.POSITIVE) {
|
||||
setAndNotify(true);
|
||||
} else {
|
||||
setAndNotify(false);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder confirm(final VolatileBox<Boolean> result) {
|
||||
onAny(new SingleButtonCallback() {
|
||||
@Override
|
||||
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
|
||||
if (which == DialogAction.POSITIVE) {
|
||||
result.setAndNotify(true);
|
||||
} else {
|
||||
result.setAndNotify(false);
|
||||
}
|
||||
}
|
||||
public MaterialDialog.Builder itemsCallback() {
|
||||
dismissListener(dialog -> setAndNotify(-1));
|
||||
super.itemsCallback((dialog, itemView, position, text) -> setAndNotify(position));
|
||||
return this;
|
||||
}
|
||||
|
||||
public MaterialDialog.Builder itemsCallbackMultiChoice(@Nullable Integer[] selectedIndices) {
|
||||
dismissListener(dialog -> setAndNotify(new Integer[0]));
|
||||
super.itemsCallbackMultiChoice(selectedIndices, (dialog, which, text) -> {
|
||||
setAndNotify(ArrayUtils.unbox(which));
|
||||
return true;
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public MaterialDialog.Builder itemsCallback(final VolatileBox<Integer> result) {
|
||||
dismissListener(result);
|
||||
super.itemsCallback(new ListCallback() {
|
||||
@Override
|
||||
public void onSelection(MaterialDialog dialog, View itemView, int position, CharSequence text) {
|
||||
result.setAndNotify(position);
|
||||
}
|
||||
public MaterialDialog.Builder itemsCallbackSingleChoice(int selectedIndex) {
|
||||
dismissListener(dialog -> setAndNotify(-1));
|
||||
super.itemsCallbackSingleChoice(selectedIndex, (dialog, itemView, which, text) -> {
|
||||
setAndNotify(which);
|
||||
return true;
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public MaterialDialog.Builder itemsCallbackMultiChoice(@Nullable Integer[] selectedIndices, final VolatileBox<Integer[]> result) {
|
||||
dismissListener(result);
|
||||
super.itemsCallbackMultiChoice(selectedIndices, new ListCallbackMultiChoice() {
|
||||
@Override
|
||||
public boolean onSelection(MaterialDialog dialog, Integer[] which, CharSequence[] text) {
|
||||
result.setAndNotify(which);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public MaterialDialog.Builder itemsCallbackSingleChoice(int selectedIndex, final VolatileBox<Integer> result) {
|
||||
dismissListener(result);
|
||||
super.itemsCallbackSingleChoice(selectedIndex, new ListCallbackSingleChoice() {
|
||||
@Override
|
||||
public boolean onSelection(MaterialDialog dialog, View itemView, int which, CharSequence text) {
|
||||
result.setAndNotify(which);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder dismissListener(final VolatileBox<?> result) {
|
||||
super.dismissListener(new OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
synchronized (result) {
|
||||
result.notify();
|
||||
}
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MaterialDialog show() {
|
||||
mUiHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Builder.super.show();
|
||||
}
|
||||
});
|
||||
return null;
|
||||
public Object showAndGet() {
|
||||
if (Looper.myLooper() == Looper.getMainLooper()) {
|
||||
super.show();
|
||||
} else {
|
||||
mUiHandler.post(Builder.super::show);
|
||||
}
|
||||
if (mResultBox != null) {
|
||||
return mResultBox.blockedGetOrThrow(ScriptInterruptedException.class);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -49,7 +49,7 @@ public interface AttributeHandler {
|
||||
if (!attr.getNodeName().equals("style")) {
|
||||
layoutXml.append("android:");
|
||||
}
|
||||
layoutXml.append(mapAttrName(nodeName, attr.getLocalName()))
|
||||
layoutXml.append(mapAttrName(nodeName, attr.getNodeName()))
|
||||
.append("=\"").append(mapAttrValue(nodeName, attr.getNodeName(), attr.getNodeValue())).append("\"\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ public class ScriptBridges {
|
||||
|
||||
Object[] NO_ARGUMENTS = new Object[0];
|
||||
|
||||
Object call(Object func, Object target, Object[] arg);
|
||||
Object call(Object func, Object target, Object arg);
|
||||
|
||||
Object toArray(Object o);
|
||||
|
||||
@@ -26,7 +26,7 @@ public class ScriptBridges {
|
||||
mBridges = bridges;
|
||||
}
|
||||
|
||||
public Object callFunction(Object func, Object target, Object[] args) {
|
||||
public Object callFunction(Object func, Object target, Object args) {
|
||||
checkBridges();
|
||||
return mBridges.call(func, target, args);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import com.stardust.autojs.runtime.exception.ScriptEnvironmentException;
|
||||
import com.stardust.autojs.runtime.exception.ScriptException;
|
||||
import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
|
||||
import com.stardust.autojs.core.accessibility.SimpleActionAutomator;
|
||||
import com.stardust.concurrent.VolatileBox;
|
||||
import com.stardust.autojs.runtime.api.UI;
|
||||
import com.stardust.concurrent.VolatileDispose;
|
||||
import com.stardust.pio.UncheckedIOException;
|
||||
@@ -38,8 +37,6 @@ import com.stardust.util.UiHandler;
|
||||
import com.stardust.view.accessibility.AccessibilityInfoProvider;
|
||||
|
||||
import org.mozilla.javascript.ContextFactory;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
import org.mozilla.javascript.ScriptableObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -174,7 +171,7 @@ public class ScriptRuntime {
|
||||
images = new Images(context, this, builder.mScreenCaptureRequester);
|
||||
}
|
||||
engines = new Engines(builder.mEngineService);
|
||||
dialogs = new Dialogs(app, mUiHandler);
|
||||
dialogs = new Dialogs(app, mUiHandler, bridges);
|
||||
}
|
||||
|
||||
public void init() {
|
||||
@@ -217,23 +214,16 @@ public class ScriptRuntime {
|
||||
}
|
||||
|
||||
public void setClip(final String text) {
|
||||
final Object lock = new Object();
|
||||
mUiHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ClipboardUtil.setClip(mUiHandler.getContext(), text);
|
||||
synchronized (lock) {
|
||||
lock.notify();
|
||||
}
|
||||
}
|
||||
});
|
||||
synchronized (lock) {
|
||||
try {
|
||||
lock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
throw new ScriptInterruptedException();
|
||||
}
|
||||
if (Looper.myLooper() == Looper.getMainLooper()) {
|
||||
ClipboardUtil.setClip(mUiHandler.getContext(), text);
|
||||
return;
|
||||
}
|
||||
VolatileDispose<Object> dispose = new VolatileDispose<>();
|
||||
mUiHandler.post(() -> {
|
||||
ClipboardUtil.setClip(mUiHandler.getContext(), text);
|
||||
dispose.setAndNotify(text);
|
||||
});
|
||||
dispose.blockedGet();
|
||||
}
|
||||
|
||||
public String getClip() {
|
||||
|
||||
@@ -9,10 +9,9 @@ import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.afollestad.materialdialogs.Theme;
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.autojs.annotation.ScriptInterface;
|
||||
import com.stardust.autojs.annotation.ScriptVariable;
|
||||
import com.stardust.autojs.core.ui.BlockedMaterialDialog;
|
||||
import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
|
||||
import com.stardust.autojs.runtime.api.AppUtils;
|
||||
import com.stardust.concurrent.VolatileBox;
|
||||
import com.stardust.autojs.runtime.ScriptBridges;
|
||||
import com.stardust.util.ArrayUtils;
|
||||
import com.stardust.util.UiHandler;
|
||||
|
||||
@@ -25,50 +24,49 @@ public class Dialogs {
|
||||
private AppUtils mAppUtils;
|
||||
private UiHandler mUiHandler;
|
||||
private ContextThemeWrapper mThemeWrapper;
|
||||
private ScriptBridges mScriptBridges;
|
||||
|
||||
public Dialogs(AppUtils appUtils, UiHandler uiHandler) {
|
||||
@ScriptVariable
|
||||
public final NonUiDialogs nonUiDialogs = new NonUiDialogs();
|
||||
|
||||
public Dialogs(AppUtils appUtils, UiHandler uiHandler, ScriptBridges scriptBridges) {
|
||||
mAppUtils = appUtils;
|
||||
mUiHandler = uiHandler;
|
||||
mScriptBridges = scriptBridges;
|
||||
}
|
||||
|
||||
@ScriptInterface
|
||||
public String rawInput(String title, String prefill) {
|
||||
VolatileBox<String> result = new VolatileBox<>(null);
|
||||
dialogBuilder()
|
||||
.input(null, prefill, true, result)
|
||||
.title(title)
|
||||
.show();
|
||||
return result.blockedGetOrThrow(ScriptInterruptedException.class);
|
||||
public Object rawInput(String title, String prefill, Object callback) {
|
||||
return ((BlockedMaterialDialog.Builder) dialogBuilder(callback)
|
||||
.input(null, prefill, true)
|
||||
.title(title))
|
||||
.showAndGet();
|
||||
}
|
||||
|
||||
|
||||
@ScriptInterface
|
||||
public void alert(String title, String content) {
|
||||
VolatileBox<Void> lock = new VolatileBox<>();
|
||||
MaterialDialog.Builder builder = dialogBuilder()
|
||||
.dismissListener(lock)
|
||||
public Object alert(String title, String content, Object callback) {
|
||||
MaterialDialog.Builder builder = dialogBuilder(callback)
|
||||
.alert()
|
||||
.title(title)
|
||||
.positiveText(R.string.ok);
|
||||
if (!TextUtils.isEmpty(content)) {
|
||||
builder.content(content);
|
||||
}
|
||||
builder.show();
|
||||
lock.blockedGetOrThrow(ScriptInterruptedException.class);
|
||||
return ((BlockedMaterialDialog.Builder) builder).showAndGet();
|
||||
}
|
||||
|
||||
@ScriptInterface
|
||||
public boolean confirm(String title, String content) {
|
||||
VolatileBox<Boolean> result = new VolatileBox<>(false);
|
||||
MaterialDialog.Builder builder = dialogBuilder()
|
||||
.dismissListener(result)
|
||||
.confirm(result)
|
||||
public Object confirm(String title, String content, Object callback) {
|
||||
MaterialDialog.Builder builder = dialogBuilder(callback)
|
||||
.confirm()
|
||||
.title(title)
|
||||
.positiveText(R.string.ok)
|
||||
.negativeText(R.string.cancel);
|
||||
if (!TextUtils.isEmpty(content)) {
|
||||
builder.content(content);
|
||||
}
|
||||
builder.show();
|
||||
return result.blockedGetOrThrow(ScriptInterruptedException.class);
|
||||
return ((BlockedMaterialDialog.Builder) builder).showAndGet();
|
||||
}
|
||||
|
||||
private Context getContext() {
|
||||
@@ -79,47 +77,99 @@ public class Dialogs {
|
||||
}
|
||||
|
||||
@ScriptInterface
|
||||
public int select(String title, String... items) {
|
||||
VolatileBox<Integer> result = new VolatileBox<>(-1);
|
||||
dialogBuilder()
|
||||
.itemsCallback(result)
|
||||
public Object select(String title, Object... args) {
|
||||
Object callback = getCallback(args);
|
||||
String[] items = getItems(args);
|
||||
return ((BlockedMaterialDialog.Builder) dialogBuilder(callback)
|
||||
.itemsCallback()
|
||||
.title(title)
|
||||
.items((CharSequence[]) items)
|
||||
.show();
|
||||
return result.blockedGetOrThrow(ScriptInterruptedException.class);
|
||||
.items((CharSequence[]) items))
|
||||
.showAndGet();
|
||||
}
|
||||
|
||||
private String[] getItems(Object[] args) {
|
||||
int len = 0;
|
||||
if (args.length > 1) {
|
||||
if (args[args.length - 1] instanceof CharSequence) {
|
||||
len = args.length;
|
||||
} else {
|
||||
len = args.length - 1;
|
||||
}
|
||||
}
|
||||
String[] items = new String[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
items[i] = args[i] == null ? null : args[i].toString();
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
private Object getCallback(Object[] args) {
|
||||
if (args.length > 1 && !(args[args.length - 1] instanceof CharSequence)) {
|
||||
return args[args.length - 1];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ScriptInterface
|
||||
public int singleChoice(String title, int selectedIndex, String... items) {
|
||||
VolatileBox<Integer> result = new VolatileBox<>(-1);
|
||||
dialogBuilder()
|
||||
.itemsCallbackSingleChoice(selectedIndex, result)
|
||||
public Object singleChoice(String title, int selectedIndex, String[] items, Object callback) {
|
||||
return ((BlockedMaterialDialog.Builder) dialogBuilder(callback)
|
||||
.itemsCallbackSingleChoice(selectedIndex)
|
||||
.title(title)
|
||||
.positiveText(R.string.ok)
|
||||
.items((CharSequence[]) items)
|
||||
.show();
|
||||
return result.blockedGetOrThrow(ScriptInterruptedException.class);
|
||||
.items((CharSequence[]) items))
|
||||
.showAndGet();
|
||||
}
|
||||
|
||||
@ScriptInterface
|
||||
public int[] multiChoice(String title, int[] indices, String... items) {
|
||||
VolatileBox<Integer[]> result = new VolatileBox<>(new Integer[0]);
|
||||
dialogBuilder()
|
||||
.itemsCallbackMultiChoice(ArrayUtils.box(indices), result)
|
||||
public Object multiChoice(String title, int[] indices, String[] items, Object callback) {
|
||||
return ((BlockedMaterialDialog.Builder) dialogBuilder(callback)
|
||||
.itemsCallbackMultiChoice(ArrayUtils.box(indices))
|
||||
.title(title)
|
||||
.positiveText(R.string.ok)
|
||||
.items((CharSequence[]) items)
|
||||
.show();
|
||||
return ArrayUtils.unbox(result.blockedGetOrThrow(ScriptInterruptedException.class));
|
||||
.items((CharSequence[]) items))
|
||||
.showAndGet();
|
||||
}
|
||||
|
||||
|
||||
private BlockedMaterialDialog.Builder dialogBuilder() {
|
||||
private BlockedMaterialDialog.Builder dialogBuilder(Object callback) {
|
||||
Context context = mAppUtils.getCurrentActivity();
|
||||
if (context == null || ((Activity) context).isFinishing()) {
|
||||
context = getContext();
|
||||
}
|
||||
return (BlockedMaterialDialog.Builder) new BlockedMaterialDialog.Builder(context, mUiHandler)
|
||||
return (BlockedMaterialDialog.Builder) new BlockedMaterialDialog.Builder(context, mUiHandler, mScriptBridges, callback)
|
||||
.theme(Theme.LIGHT);
|
||||
}
|
||||
|
||||
public class NonUiDialogs {
|
||||
|
||||
public String rawInput(String title, String prefill, Object callback) {
|
||||
return (String) Dialogs.this.rawInput(title, prefill, callback);
|
||||
}
|
||||
|
||||
@ScriptInterface
|
||||
public boolean confirm(String title, String content, Object callback) {
|
||||
return (boolean) Dialogs.this.confirm(title, content, callback);
|
||||
}
|
||||
|
||||
@ScriptInterface
|
||||
public int select(String title, Object... args) {
|
||||
return (Integer) Dialogs.this.select(title, args);
|
||||
}
|
||||
|
||||
@ScriptInterface
|
||||
public int singleChoice(String title, int selectedIndex, String[] items, Object callback) {
|
||||
return (int) Dialogs.this.singleChoice(title, selectedIndex, items, callback);
|
||||
}
|
||||
|
||||
@ScriptInterface
|
||||
public int[] multiChoice(String title, int[] indices, String[] items, Object callback) {
|
||||
return (int[]) Dialogs.this.multiChoice(title, indices, items, callback);
|
||||
}
|
||||
|
||||
@ScriptInterface
|
||||
public Object alert(String title, String content, Object callback) {
|
||||
return Dialogs.this.alert(title, content, callback);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user