From 7b1a5fc6750a39b4fd4ad426854d22ea4bf40cd1 Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Tue, 15 Aug 2017 21:12:58 +0800 Subject: [PATCH] fix: setInterval & setTimeout not working when waitWhenIdle is false --- .../需要Root权限的自动操作函数.md | 6 +-- .../autojs/runtime/ScriptRuntime.java | 4 +- .../stardust/autojs/runtime/api/Loopers.java | 22 ++++++-- .../stardust/autojs/runtime/api/Timers.java | 54 +++++++++++-------- 4 files changed, 54 insertions(+), 32 deletions(-) diff --git a/app/src/main/assets/help/documentation/需要Root权限的自动操作函数.md b/app/src/main/assets/help/documentation/需要Root权限的自动操作函数.md index 15fb4bfe..4acfd791 100644 --- a/app/src/main/assets/help/documentation/需要Root权限的自动操作函数.md +++ b/app/src/main/assets/help/documentation/需要Root权限的自动操作函数.md @@ -58,13 +58,13 @@ for(var i = 0; i < 100; i++){ 模拟按下物理按键上。 ### Down() -模拟按下物理按键上。 +模拟按下物理按键下。 ### Left() -模拟按下物理按键上。 +模拟按下物理按键左。 ### Right() -模拟按下物理按键上。 +模拟按下物理按键右。 ### OK() 模拟按下物理按键确定。 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 4c4682fe..af41f30e 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java @@ -177,9 +177,9 @@ public class ScriptRuntime { public void init() { if (loopers != null) throw new IllegalStateException("already initialized"); - loopers = new Loopers(); - events = new Events(mUiHandler.getContext(), accessibilityBridge, bridges, loopers); timers = new Timers(bridges); + loopers = new Loopers(timers); + events = new Events(mUiHandler.getContext(), accessibilityBridge, bridges, loopers); } public static void setApplicationContext(Context context) { diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/Loopers.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/Loopers.java index 6a7775b0..c0dffdc3 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/api/Loopers.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/Loopers.java @@ -6,6 +6,7 @@ import android.os.MessageQueue; import com.stardust.autojs.runtime.exception.ScriptInterruptedException; import com.stardust.lang.ThreadCompat; +import java.lang.reflect.Field; import java.util.concurrent.ConcurrentHashMap; /** @@ -14,26 +15,37 @@ import java.util.concurrent.ConcurrentHashMap; public class Loopers { + public volatile boolean waitWhenIdle = false; private volatile Looper mServantLooper; private static volatile ConcurrentHashMap sLoopers = new ConcurrentHashMap<>(); + private static Field MESSAGE_QUEUE_MESSAGE; + private Timers mTimers; + private MessageQueue mMessageQueue; - public volatile boolean waitWhenIdle = false; - - public Loopers() { + public Loopers(Timers timers) { + mTimers = timers; if (Looper.myLooper() == Looper.getMainLooper()) { waitWhenIdle = true; } - Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() { + mMessageQueue = Looper.myQueue(); + mMessageQueue.addIdleHandler(new MessageQueue.IdleHandler() { @Override public boolean queueIdle() { Looper l = Looper.myLooper(); - if (l != null && !waitWhenIdle) + if (l != null && shouldQuitLooper()) l.quit(); return true; } }); } + private boolean shouldQuitLooper() { + if (mTimers.hasPendingCallback()) { + return false; + } + return !waitWhenIdle; + } + private void initServantThread() { new ThreadCompat(new Runnable() { 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 eee7f4a8..bd747811 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 @@ -1,6 +1,7 @@ package com.stardust.autojs.runtime.api; import android.os.Handler; +import android.os.SystemClock; import android.util.SparseArray; import com.stardust.autojs.runtime.ScriptBridges; @@ -15,19 +16,20 @@ public class Timers { private int mCallbackMaxId = 0; private ScriptBridges mBridges; private Handler mHandler; + private long mFutureCallbackUptimeMillis = 0; public Timers(ScriptBridges bridges) { mBridges = bridges; } - private void ensureHander(){ - if(mHandler == null){ + private void ensureHandler() { + if (mHandler == null) { mHandler = new Handler(); } } public int setTimeout(final Object callback, long delay, final Object... args) { - ensureHander(); + ensureHandler(); mCallbackMaxId++; final int id = mCallbackMaxId; Runnable r = new Runnable() { @@ -38,41 +40,44 @@ public class Timers { } }; mHandlerCallbacks.put(id, r); - mHandler.postDelayed(r, delay); + postDelayed(r, delay); return id; } - public void post(Runnable r) { - ensureHander(); - mHandler.post(r); - } - - public void clearTimeout(int id) { - clearCallback(id); + public boolean clearTimeout(int id) { + return clearCallback(id); } public int setInterval(final Object listener, final long interval, final Object... args) { - ensureHander(); + ensureHandler(); mCallbackMaxId++; final int id = mCallbackMaxId; - Runnable r = new Runnable() { + final Runnable r = new Runnable() { @Override public void run() { + if (mHandlerCallbacks.get(id) == null) + return; mBridges.callFunction(listener, null, args); - mHandler.postDelayed(this, interval); + postDelayed(this, interval); } }; mHandlerCallbacks.put(id, r); - mHandler.postDelayed(r, interval); + postDelayed(r, interval); return id; } - public void clearInterval(int id) { - clearTimeout(id); + private void postDelayed(Runnable r, long interval) { + long uptime = SystemClock.uptimeMillis() + interval; + mHandler.postAtTime(r, uptime); + mFutureCallbackUptimeMillis = Math.max(mFutureCallbackUptimeMillis, uptime); + } + + public boolean clearInterval(int id) { + return clearCallback(id); } public int setImmediate(final Object listener, final Object... args) { - ensureHander(); + ensureHandler(); mCallbackMaxId++; final int id = mCallbackMaxId; Runnable r = new Runnable() { @@ -83,21 +88,26 @@ public class Timers { } }; mHandlerCallbacks.put(id, r); - mHandler.post(r); + postDelayed(r, 0); return id; } - public void clearImmediate(int id) { - clearCallback(id); + public boolean clearImmediate(int id) { + return clearCallback(id); } - private void clearCallback(int id) { + private boolean clearCallback(int id) { Runnable callback = mHandlerCallbacks.get(id); if (callback != null) { mHandler.removeCallbacks(callback); mHandlerCallbacks.remove(id); + return true; } + return false; } + public boolean hasPendingCallback() { + return mFutureCallbackUptimeMillis > SystemClock.uptimeMillis(); + } }