From baaa820d097183e7d2fcfed29550236450d27c8e Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Wed, 18 Apr 2018 17:48:26 +0800 Subject: [PATCH] api(dialogs): change dialog event callback thread to caller thread --- autojs/src/main/assets/modules/__dialogs__.js | 6 ++- .../stardust/autojs/core/looper/Loopers.java | 19 +++++++- .../autojs/core/ui/dialog/JsDialog.java | 43 +++++++++++-------- .../core/ui/dialog/JsDialogBuilder.java | 28 +++++++++--- .../autojs/runtime/ScriptRuntime.java | 2 +- .../stardust/autojs/runtime/api/Dialogs.java | 21 ++++----- .../stardust/autojs/runtime/api/Timers.java | 2 +- 7 files changed, 80 insertions(+), 41 deletions(-) diff --git a/autojs/src/main/assets/modules/__dialogs__.js b/autojs/src/main/assets/modules/__dialogs__.js index 4f84fe23..26e78254 100644 --- a/autojs/src/main/assets/modules/__dialogs__.js +++ b/autojs/src/main/assets/modules/__dialogs__.js @@ -119,11 +119,13 @@ module.exports = function(__runtime__, scope){ "negative": {method: "negativeText"}, "negativeColor": {adapter: parseColor}, "cancelable": null, - "canceledOnTouchOutside": null + "canceledOnTouchOutside": null, + autoDismiss: null }; dialogs.build = function(properties){ - var builder = __runtime__.dialogs.newBuilder(); + var builder = Object.create(__runtime__.dialogs.newBuilder()); + builder.thread = threads.currentThread(); for(var name in properties){ if(!properties.hasOwnProperty(name)){ continue; diff --git a/autojs/src/main/java/com/stardust/autojs/core/looper/Loopers.java b/autojs/src/main/java/com/stardust/autojs/core/looper/Loopers.java index 491c578c..203d4857 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/looper/Loopers.java +++ b/autojs/src/main/java/com/stardust/autojs/core/looper/Loopers.java @@ -5,12 +5,14 @@ import android.os.Looper; import android.os.MessageQueue; import android.util.Log; +import com.android.dx.util.IntSet; import com.stardust.autojs.runtime.ScriptRuntime; import com.stardust.autojs.runtime.api.Threads; import com.stardust.autojs.runtime.api.Timers; import com.stardust.autojs.runtime.exception.ScriptInterruptedException; import com.stardust.lang.ThreadCompat; +import java.util.HashSet; import java.util.concurrent.CopyOnWriteArrayList; /** @@ -29,6 +31,8 @@ public class Loopers implements MessageQueue.IdleHandler { }; private volatile ThreadLocal waitWhenIdle = new ThreadLocal<>(); + private volatile ThreadLocal> waitIds = new ThreadLocal<>(); + private volatile ThreadLocal maxWaitId = new ThreadLocal<>(); private volatile ThreadLocal> looperQuitHanders = new ThreadLocal<>(); private volatile Looper mServantLooper; private Timers mTimers; @@ -75,7 +79,7 @@ public class Loopers implements MessageQueue.IdleHandler { if (mTimers.hasPendingCallbacks()) { return false; } - if (waitWhenIdle.get()) { + if (waitWhenIdle.get() || !waitIds.get().isEmpty()) { return false; } CopyOnWriteArrayList handlers = looperQuitHanders.get(); @@ -123,6 +127,17 @@ public class Loopers implements MessageQueue.IdleHandler { mServantLooper.quit(); } + public int waitWhenIdle() { + int id = maxWaitId.get(); + maxWaitId.set(id + 1); + waitIds.get().add(id); + return id; + } + + public void doNotWaitWhenIdle(int waitId) { + waitIds.get().remove(waitId); + } + public void waitWhenIdle(boolean b) { waitWhenIdle.set(b); } @@ -162,6 +177,8 @@ public class Loopers implements MessageQueue.IdleHandler { LooperHelper.prepare(); Looper.myQueue().addIdleHandler(this); waitWhenIdle.set(Looper.myLooper() == Looper.getMainLooper()); + waitIds.set(new HashSet<>()); + maxWaitId.set(0); } public void notifyThreadExit(TimerThread thread) { diff --git a/autojs/src/main/java/com/stardust/autojs/core/ui/dialog/JsDialog.java b/autojs/src/main/java/com/stardust/autojs/core/ui/dialog/JsDialog.java index df70ff49..d64440c8 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/ui/dialog/JsDialog.java +++ b/autojs/src/main/java/com/stardust/autojs/core/ui/dialog/JsDialog.java @@ -53,13 +53,35 @@ public class JsDialog { private final EventEmitter mEmitter; private final UiHandler mUiHandler; private final MaterialDialog mDialog; + private final JsDialogBuilder mBuilder; - public JsDialog(MaterialDialog dialog, EventEmitter emitter, UiHandler uiHandler) { - mDialog = dialog; + public JsDialog(JsDialogBuilder builder, EventEmitter emitter, UiHandler uiHandler) { + mBuilder = builder; + mDialog = builder.build(); mEmitter = emitter; mUiHandler = uiHandler; } + public JsDialog show() { + checkWindowType(); + if (Looper.myLooper() == Looper.getMainLooper()) { + mDialog.show(); + } else { + mUiHandler.post(mDialog::show); + } + mBuilder.onShowCalled(); + return this; + } + + private void checkWindowType() { + Context context = mDialog.getContext(); + if (!DialogUtils.isActivityContext(context)) { + Window window = mDialog.getWindow(); + if (window != null) + window.setType(WindowManager.LayoutParams.TYPE_PHONE); + } + } + public MaterialDialog.Builder getBuilder() { return mDialog.getBuilder(); } @@ -695,22 +717,5 @@ public class JsDialog { return EventEmitter.defaultMaxListeners(); } - public JsDialog show() { - checkWindowType(); - if (Looper.myLooper() == Looper.getMainLooper()) { - mDialog.show(); - } else { - mUiHandler.post(mDialog::show); - } - return this; - } - private void checkWindowType() { - Context context = mDialog.getContext(); - if (!DialogUtils.isActivityContext(context)) { - Window window = mDialog.getWindow(); - if (window != null) - window.setType(WindowManager.LayoutParams.TYPE_PHONE); - } - } } diff --git a/autojs/src/main/java/com/stardust/autojs/core/ui/dialog/JsDialogBuilder.java b/autojs/src/main/java/com/stardust/autojs/core/ui/dialog/JsDialogBuilder.java index 4f54104e..17d6fde0 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/ui/dialog/JsDialogBuilder.java +++ b/autojs/src/main/java/com/stardust/autojs/core/ui/dialog/JsDialogBuilder.java @@ -18,7 +18,11 @@ import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.materialdialogs.StackingBehavior; import com.afollestad.materialdialogs.Theme; import com.stardust.autojs.core.eventloop.EventEmitter; +import com.stardust.autojs.core.looper.Loopers; +import com.stardust.autojs.core.looper.Timer; +import com.stardust.autojs.core.looper.TimerThread; import com.stardust.autojs.runtime.ScriptBridges; +import com.stardust.autojs.runtime.ScriptRuntime; import com.stardust.util.ArrayUtils; import com.stardust.util.UiHandler; @@ -33,12 +37,18 @@ public class JsDialogBuilder extends MaterialDialog.Builder { private final EventEmitter mEmitter; private final UiHandler mUiHandler; + private final Timer mTimer; + private final Loopers mLoopers; private JsDialog mDialog; + private volatile int mWaitId = -1; - public JsDialogBuilder(@NonNull Context context, ScriptBridges bridges, UiHandler uiHandler) { + + public JsDialogBuilder(Context context, ScriptRuntime runtime) { super(context); - mEmitter = new EventEmitter(bridges); - this.mUiHandler = uiHandler; + mTimer = runtime.timers.getTimerForCurrentThread(); + mLoopers = runtime.loopers; + mEmitter = new EventEmitter(runtime.bridges, mTimer); + mUiHandler = runtime.uiHandler; setUpEvents(); } @@ -64,16 +74,24 @@ public class JsDialogBuilder extends MaterialDialog.Builder { break; } }); - dismissListener(dialog -> emit("dismiss", dialog)); + dismissListener(dialog -> { + mTimer.postDelayed(() -> mLoopers.doNotWaitWhenIdle(mWaitId), 0); + emit("dismiss", dialog); + }); cancelListener(dialog -> emit("cancel", dialog)); } + public void onShowCalled() { + mTimer.postDelayed(() -> mWaitId = mLoopers.waitWhenIdle(), 0); + + } + public JsDialog getDialog() { return mDialog; } public JsDialog buildDialog() { - mDialog = new JsDialog(super.build(), mEmitter, mUiHandler); + mDialog = new JsDialog(this, mEmitter, mUiHandler); return mDialog; } diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java b/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java index bc915979..8a22fabc 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java @@ -212,7 +212,7 @@ public class ScriptRuntime { images = new Images(context, this, builder.mScreenCaptureRequester); } engines = new Engines(builder.mEngineService, this); - dialogs = new Dialogs(app, uiHandler, bridges); + dialogs = new Dialogs(this); device = new Device(context); floaty = new Floaty(uiHandler, ui, this); files = new Files(this); diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/Dialogs.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/Dialogs.java index 6e9ec4b3..b5a2f2de 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/api/Dialogs.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/Dialogs.java @@ -14,6 +14,7 @@ import com.stardust.autojs.annotation.ScriptVariable; import com.stardust.autojs.core.ui.dialog.BlockedMaterialDialog; import com.stardust.autojs.core.ui.dialog.JsDialogBuilder; import com.stardust.autojs.runtime.ScriptBridges; +import com.stardust.autojs.runtime.ScriptRuntime; import com.stardust.util.ArrayUtils; import com.stardust.util.UiHandler; @@ -23,18 +24,14 @@ import com.stardust.util.UiHandler; public class Dialogs { - private AppUtils mAppUtils; - private UiHandler mUiHandler; private ContextThemeWrapper mThemeWrapper; - private ScriptBridges mScriptBridges; + private final ScriptRuntime mRuntime; @ScriptVariable public final NonUiDialogs nonUiDialogs = new NonUiDialogs(); - public Dialogs(AppUtils appUtils, UiHandler uiHandler, ScriptBridges scriptBridges) { - mAppUtils = appUtils; - mUiHandler = uiHandler; - mScriptBridges = scriptBridges; + public Dialogs(ScriptRuntime runtime) { + mRuntime = runtime; } @ScriptInterface @@ -74,7 +71,7 @@ public class Dialogs { private Context getContext() { if (mThemeWrapper != null) return mThemeWrapper; - mThemeWrapper = new ContextThemeWrapper(mUiHandler.getContext().getApplicationContext(), R.style.Theme_AppCompat_Light); + mThemeWrapper = new ContextThemeWrapper(mRuntime.uiHandler.getContext().getApplicationContext(), R.style.Theme_AppCompat_Light); return mThemeWrapper; } @@ -138,21 +135,21 @@ public class Dialogs { private BlockedMaterialDialog.Builder dialogBuilder(Object callback) { - Context context = mAppUtils.getCurrentActivity(); + Context context = mRuntime.app.getCurrentActivity(); if (context == null || ((Activity) context).isFinishing()) { context = getContext(); } - return (BlockedMaterialDialog.Builder) new BlockedMaterialDialog.Builder(context, mUiHandler, mScriptBridges, callback) + return (BlockedMaterialDialog.Builder) new BlockedMaterialDialog.Builder(context, mRuntime.uiHandler, mRuntime.bridges, callback) .theme(Theme.LIGHT); } @ScriptInterface public MaterialDialog.Builder newBuilder() { - Context context = mAppUtils.getCurrentActivity(); + Context context = mRuntime.app.getCurrentActivity(); if (context == null || ((Activity) context).isFinishing()) { context = getContext(); } - return new JsDialogBuilder(context, mScriptBridges, mUiHandler) + return new JsDialogBuilder(context, mRuntime) .theme(Theme.LIGHT); } diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/Timers.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/Timers.java index 96d5b2dc..a7ca64d5 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/api/Timers.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/Timers.java @@ -39,7 +39,7 @@ public class Timers { return mMaxCallbackUptimeMillisForAllThreads; } - private Timer getTimerForCurrentThread() { + public Timer getTimerForCurrentThread() { return getTimerForThread(Thread.currentThread()); }