From 9ffca282074089efd8e1f5c559bca57c8544143c Mon Sep 17 00:00:00 2001 From: SuperMonster003 Date: Sat, 31 Jan 2026 18:52:24 +0800 Subject: [PATCH] 6.7.0 - Alpha19 - Fine tuning --- .../autojs/app/tool/PointerLocationTool.kt | 2 +- .../autojs/autojs/core/looper/LooperThread.kt | 2 +- .../autojs/autojs/core/looper/TimerThread.kt | 126 +++++++++--------- .../org/autojs/autojs/rhino/debug/Dim.java | 7 +- .../autojs/autojs/runtime/api/Dialogs.java | 10 +- .../java/org/autojs/autojs/runtime/api/UI.kt | 2 +- .../org/autojs/autojs/runtime/api/Util.kt | 2 +- .../autojs/runtime/api/WrappedShizuku.kt | 11 +- .../autojs/runtime/api/augment/Augmentable.kt | 2 +- .../runtime/api/augment/images/Images.kt | 2 +- .../augment/jsox/JsBuildInObjectExtensible.kt | 2 +- .../autojs/runtime/api/augment/shell/Shell.kt | 28 ++-- .../runtime/api/augment/shizuku/Shizuku.kt | 1 + .../autojs/ui/floating/CircularMenu.java | 19 ++- version.properties | 6 +- 15 files changed, 123 insertions(+), 99 deletions(-) diff --git a/app/src/main/java/org/autojs/autojs/app/tool/PointerLocationTool.kt b/app/src/main/java/org/autojs/autojs/app/tool/PointerLocationTool.kt index 90829d9f..7280a2dc 100644 --- a/app/src/main/java/org/autojs/autojs/app/tool/PointerLocationTool.kt +++ b/app/src/main/java/org/autojs/autojs/app/tool/PointerLocationTool.kt @@ -98,7 +98,7 @@ open class PointerLocationTool(final override val context: Context) : ShowableIt runCatching byShizuku@{ when { - WrappedShizuku.isOperational() -> { + WrappedShizuku.hasService() && WrappedShizuku.isOperational() -> { WrappedShizuku.execCommand(context, cmd).result.trim().toIntOrNull() } else -> null diff --git a/app/src/main/java/org/autojs/autojs/core/looper/LooperThread.kt b/app/src/main/java/org/autojs/autojs/core/looper/LooperThread.kt index 50123b8b..e8d88c37 100644 --- a/app/src/main/java/org/autojs/autojs/core/looper/LooperThread.kt +++ b/app/src/main/java/org/autojs/autojs/core/looper/LooperThread.kt @@ -12,7 +12,7 @@ object LooperThread { fun getLooperOrNull(thread: Thread) = when { isEqual(thread, Looper.getMainLooper().thread) -> Looper.getMainLooper() - thread is ILooperThread -> (thread as ILooperThread).looper + thread is ILooperThread -> thread.looper else -> null } diff --git a/app/src/main/java/org/autojs/autojs/core/looper/TimerThread.kt b/app/src/main/java/org/autojs/autojs/core/looper/TimerThread.kt index 0ef6af10..db2bb8c4 100644 --- a/app/src/main/java/org/autojs/autojs/core/looper/TimerThread.kt +++ b/app/src/main/java/org/autojs/autojs/core/looper/TimerThread.kt @@ -12,18 +12,19 @@ import org.autojs.autojs.runtime.exception.ScriptInterruptedException import org.mozilla.javascript.BaseFunction import org.mozilla.javascript.Context import java.lang.ref.WeakReference -import java.util.* +import java.util.WeakHashMap +import java.util.concurrent.CountDownLatch /** * Created by Stardust on Dec 27, 2017. + * Modified by SuperMonster003 as of Jan 31, 2026. */ open class TimerThread( scriptRuntime: ScriptRuntime, private val target: Runnable, ) : ThreadCompat(target), ILooperThread { - private var mRunning = false - private val mRunningLock = Object() + private val mRunningLatch = CountDownLatch(1) private var mWeakRuntime = WeakReference(scriptRuntime) @Volatile @@ -32,54 +33,43 @@ open class TimerThread( @Volatile private var mLooper: Looper? = null - override val looper: Looper? = mLooper - - var loopers: Loopers? = null - - val timer: Timer - get() { - checkNotNull(mTimer) { "thread is not alive" } - return mTimer as Timer - } + override val looper: Looper? + get() = mLooper override fun run() { val scriptRuntime = mWeakRuntime.get() ?: return + scriptRuntime.loopers.prepare() - var timer: Timer - mTimer = scriptRuntime.timers.newTimer(scriptRuntime).also { timer = it } - sTimerMap[currentThread()] = WeakReference(timer) - (scriptRuntime.engines.myEngine() as? RhinoJavaScriptEngine)?.enterContext() + + scriptRuntime.timers.newTimer(scriptRuntime).also { + mTimer = it + sTimerMap[currentThread()] = WeakReference(it) + } + + val engine = scriptRuntime.engines.myEngine() as? RhinoJavaScriptEngine + engine?.enterContext() + notifyRunning() - Looper.myLooper().also { setLooper(it) } - ?.let { Handler(it).post(target) } - try { - Looper.loop() - onExit() - mTimer = null - } catch (throwable: Throwable) { - try { - if (ScriptInterruptedException.causedByInterrupt(throwable)) { - return + + val currentLooper = Looper.myLooper() + setLooper(currentLooper) + currentLooper?.let { Handler(it).post(target) } + + val exceptionHandler: (t: Throwable) -> Unit = { t -> + runCatching { + if (!ScriptInterruptedException.causedByInterrupt(t)) { + val console: Console = mWeakRuntime.get()?.console ?: AutoJs.instance.globalConsole + console.error("${currentThread()}: $t") } - var console: Console? = null - val runtime = mWeakRuntime.get() - if (runtime != null) { - console = runtime.console - } - if (console == null) { - console = AutoJs.instance.globalConsole - } - console.error("${Thread.currentThread()}: $throwable") - } finally { - onExit() - mTimer = null - Context.exit() - sTimerMap.remove(currentThread()) } } - runCatching { Context.exit() } - sTimerMap.remove(currentThread()) - } + + runCatching { Looper.loop() }.onFailure(exceptionHandler) + runCatching { onExit() }.onFailure(exceptionHandler) + mTimer = null + runCatching { Context.exit() }.onFailure(exceptionHandler) + sTimerMap.remove(currentThread()) + } override fun interrupt() { LooperHelper.quit(LooperThread.getLooperOrNull(this)) @@ -96,46 +86,58 @@ open class TimerThread( @Throws(InterruptedException::class) fun waitFor() { - synchronized(mRunningLock) { - if (!mRunning) { - mRunningLock.wait() - } - } + mRunningLatch.await() } - fun setTimeout(callback: BaseFunction): Double = setTimeout(callback, 1) + fun setTimeout(callback: BaseFunction): Double = + setTimeout(callback, 1) - fun setTimeout(callback: BaseFunction, delay: Long, vararg args: Any): Double = timer.setTimeout(callback, delay, args.copyOf()) + fun setTimeout(callback: BaseFunction, delay: Long, vararg args: Any): Double = withTimer { + setTimeout(callback, delay, args.copyOf()) + } - fun clearTimeout(id: Double) = timer.clearTimeout(id) + fun clearTimeout(id: Double): Boolean = withTimer { + clearTimeout(id) + } - fun setInterval(callback: BaseFunction) = setInterval(callback, 1L) + fun setInterval(callback: BaseFunction): Double = + setInterval(callback, 1L) - fun setInterval(callback: BaseFunction, interval: Long, vararg args: Any) = timer.setInterval(callback, interval, args.copyOf()) + fun setInterval(callback: BaseFunction, interval: Long, vararg args: Any): Double = withTimer { + setInterval(callback, interval, args.copyOf()) + } - fun clearInterval(id: Double) = timer.clearInterval(id) + fun clearInterval(id: Double): Boolean = withTimer { + clearInterval(id) + } - fun setImmediate(callback: BaseFunction, vararg args: Any) = timer.setImmediate(callback, args.copyOf()) + fun setImmediate(callback: BaseFunction, vararg args: Any): Double = withTimer { + setImmediate(callback, args.copyOf()) + } - fun clearImmediate(id: Double) = timer.clearImmediate(id) + fun clearImmediate(id: Double): Boolean = withTimer { + clearImmediate(id) + } + + private inline fun withTimer(callback: Timer.() -> R): R { + val timer = mTimer + checkNotNull(timer) { "Thread is not alive" } + return callback(timer) + } private fun setLooper(looper: Looper?) { mLooper = looper } private fun notifyRunning() { - synchronized(mRunningLock) { - mRunning = true - mRunningLock.notifyAll() - } + mRunningLatch.countDown() } companion object { + private val sTimerMap = WeakHashMap>() @JvmStatic fun getTimerForThread(thread: Thread) = sTimerMap[thread]?.get() - } - } \ No newline at end of file diff --git a/app/src/main/java/org/autojs/autojs/rhino/debug/Dim.java b/app/src/main/java/org/autojs/autojs/rhino/debug/Dim.java index cedd1666..94ccc40c 100644 --- a/app/src/main/java/org/autojs/autojs/rhino/debug/Dim.java +++ b/app/src/main/java/org/autojs/autojs/rhino/debug/Dim.java @@ -1037,10 +1037,9 @@ public class Dim { @Override public void onEngineCreate(ScriptEngine engine) { if (type != IPROXY_LISTEN) Kit.codeBug(); - if (!(engine instanceof RhinoJavaScriptEngine) || - !callback.shouldAttachDebugger((RhinoJavaScriptEngine) engine)) { - return; - } + + if (!(engine instanceof RhinoJavaScriptEngine)) return; + if (!callback.shouldAttachDebugger((RhinoJavaScriptEngine) engine)) return; Context cx = ((RhinoJavaScriptEngine) engine).getContext(); ContextData contextData = new ContextData(); diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/Dialogs.java b/app/src/main/java/org/autojs/autojs/runtime/api/Dialogs.java index df7da250..5f296b08 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/Dialogs.java +++ b/app/src/main/java/org/autojs/autojs/runtime/api/Dialogs.java @@ -45,7 +45,7 @@ public class Dialogs { MaterialDialog.Builder builder = dialogBuilder(callback) .alert() .title(title) - .positiveText(R.string.text_ok); + .positiveText(R.string.dialog_button_dismiss); if (!TextUtils.isEmpty(content)) { builder.content(content); } @@ -57,8 +57,8 @@ public class Dialogs { MaterialDialog.Builder builder = dialogBuilder(callback) .confirm() .title(title) - .positiveText(R.string.text_ok) - .negativeText(R.string.text_cancel); + .positiveText(R.string.dialog_button_confirm) + .negativeText(R.string.dialog_button_cancel); if (!TextUtils.isEmpty(content)) { builder.content(content); } @@ -86,7 +86,7 @@ public class Dialogs { return ((BlockedMaterialDialog.Builder) dialogBuilder(callback) .itemsCallbackSingleChoice(selectedIndex) .title(title) - .positiveText(R.string.text_ok) + .positiveText(R.string.dialog_button_confirm) .items(items)) .showAndGet(); } @@ -96,7 +96,7 @@ public class Dialogs { return ((BlockedMaterialDialog.Builder) dialogBuilder(callback) .itemsCallbackMultiChoice(ArrayUtils.box(indices)) .title(title) - .positiveText(R.string.text_ok) + .positiveText(R.string.dialog_button_confirm) .items(items)) .showAndGet(); } diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/UI.kt b/app/src/main/java/org/autojs/autojs/runtime/api/UI.kt index 08ba6720..a0df20e6 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/UI.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/UI.kt @@ -43,7 +43,7 @@ class UI(context: Context, private val scriptRuntime: ScriptRuntime) : ProxyObje it.context = context } - private val mProperties = ConcurrentHashMap().also { + private val mProperties = ConcurrentHashMap().also { it["layoutInflater"] = layoutInflater } diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/Util.kt b/app/src/main/java/org/autojs/autojs/runtime/api/Util.kt index 74c31b66..c8ae3b89 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/Util.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/Util.kt @@ -13,7 +13,7 @@ object Util { fun getClassName(o: Any?) = getClassNameInternal(o, "getClassName") private fun getClassInternal(o: Any?, methodName: String): Class { - require(o != null) { "Argument \"o\" ${o.jsBrief()} for util.$methodName must be non-null" } + requireNotNull(o) { "Argument \"o\" ${o.jsBrief()} for util.$methodName must be non-null" } return o as? Class<*> ?: o.javaClass } diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/WrappedShizuku.kt b/app/src/main/java/org/autojs/autojs/runtime/api/WrappedShizuku.kt index 3f086700..ad956630 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/WrappedShizuku.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/WrappedShizuku.kt @@ -139,7 +139,7 @@ object WrappedShizuku { } @ScriptInterface - fun isOperational() = hasService() && isRunning() && hasPermission() + fun isOperational() = isRunning() && hasPermission() @ScriptInterface fun isRunning() = mHasBinder @@ -147,6 +147,15 @@ object WrappedShizuku { @ScriptInterface fun hasService() = service != null + @JvmStatic + fun getServiceOrNull(): IUserService? { + service?.let { return it } + bindUserServiceIfNeeded() + initializeShizukuServiceAndWait(5000L) + service?.let { return it } + return null + } + @ScriptInterface fun requestPermission() = Shizuku.requestPermission(mRequestCode) diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/Augmentable.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/Augmentable.kt index 989c53b6..226709d3 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/Augmentable.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/Augmentable.kt @@ -266,7 +266,7 @@ abstract class Augmentable(private val scriptRuntime: ScriptRuntime? = null) : A } if (this is AsEmitter) { - require(scriptRuntime != null) { "Augmentable instance of AsEmitter must have a non-null scriptRuntime property" } + requireNotNull(scriptRuntime) { "Augmentable instance of AsEmitter must have a non-null scriptRuntime property" } objProtoList += Events.__asEmitter__(scriptRuntime, emptyArray()) } diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/images/Images.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/images/Images.kt index af8b5988..9e5d0737 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/images/Images.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/images/Images.kt @@ -1170,7 +1170,7 @@ class Images(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitt var bitmap: Bitmap? = null try { image = read(scriptRuntime, argList) - require(image != null) { "Image path ${argList[0]} is invalid for images.readPixels" } + requireNotNull(image) { "Image path ${argList[0]} is invalid for images.readPixels" } bitmap = image.bitmap val w = bitmap.width val h = bitmap.height diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/jsox/JsBuildInObjectExtensible.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/jsox/JsBuildInObjectExtensible.kt index 53951c1a..3ce7f9aa 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/jsox/JsBuildInObjectExtensible.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/jsox/JsBuildInObjectExtensible.kt @@ -81,7 +81,7 @@ internal fun extendBuildInObjectInternal(scriptRuntime: ScriptRuntime, augmentab } protoList.forEach { pair -> val (funcName, attributes) = pair - require(extensibleProtoClass != null) { "A proto class must be specified for build-in object prototype extension" } + requireNotNull(extensibleProtoClass) { "A proto class must be specified for build-in object prototype extension" } val prototypeObject = buildInObject.prop("prototype") as ScriptableObject diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/shell/Shell.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/shell/Shell.kt index 367d0eea..d67434ee 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/shell/Shell.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/shell/Shell.kt @@ -3,9 +3,14 @@ package org.autojs.autojs.runtime.api.augment.shell import android.util.Log import android.view.KeyEvent import org.autojs.autojs.annotation.RhinoRuntimeFunctionInterface +import org.autojs.autojs.rhino.ArgumentGuards +import org.autojs.autojs.rhino.ArgumentGuards.Companion.component1 +import org.autojs.autojs.rhino.ArgumentGuards.Companion.component2 +import org.autojs.autojs.rhino.ArgumentGuards.Companion.component3 +import org.autojs.autojs.rhino.ArgumentGuards.Companion.component4 +import org.autojs.autojs.rhino.ArgumentGuards.Companion.component5 import org.autojs.autojs.rhino.extension.AnyExtensions.isJsNullish import org.autojs.autojs.rhino.extension.AnyExtensions.jsBrief -import org.autojs.autojs.rhino.ArgumentGuards import org.autojs.autojs.runtime.ScriptRuntime import org.autojs.autojs.runtime.api.AbstractShell import org.autojs.autojs.runtime.api.augment.Augmentable @@ -132,16 +137,17 @@ class Shell(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntim process.inputStream.bufferedReader().useLines { lines -> val resumedActivityLine = lines.find { it.contains("Resumed:") || it.contains("ResumedActivity") - } - resumedActivityLine?.let { line -> - Log.d(TAG, "Found Resumed Activity: $line") - line.split("\\s+".toRegex()).firstOrNull { part -> - part.contains("/") - }?.let { part -> - Log.d(TAG, "current activity part: $part") - return part.replace("\\W+$".toRegex(), "") - } - } + } ?: return@useLines + + Log.d(TAG, "Found Resumed Activity: $resumedActivityLine") + + val activityPart = resumedActivityLine.split("\\s+".toRegex()).firstOrNull { part -> + part.contains("/") + } ?: return@useLines + + Log.d(TAG, "current activity part: $activityPart") + + return activityPart.replace("\\W+$".toRegex(), "") } } catch (e: Exception) { Log.e(TAG, "Error reading current component", e) diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/shizuku/Shizuku.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/shizuku/Shizuku.kt index 52f501a1..87f82b87 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/shizuku/Shizuku.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/shizuku/Shizuku.kt @@ -28,6 +28,7 @@ class Shizuku(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRunt "state" to Supplier { newNativeObject().also { o -> o.defineProp("isInstalled", WrappedShizuku.isInstalled(globalContext)) + o.defineProp("hasService", WrappedShizuku.hasService()) o.defineProp("isRunning", WrappedShizuku.isRunning()) o.defineProp("hasPermission", WrappedShizuku.hasPermission()) o.defineProp("isOperational", WrappedShizuku.isOperational()) diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java b/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java index 16a0b279..9b4f5af4 100644 --- a/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java +++ b/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java @@ -24,6 +24,7 @@ import org.autojs.autojs.core.pref.Language; import org.autojs.autojs.core.pref.Pref; import org.autojs.autojs.core.record.GlobalActionRecorder; import org.autojs.autojs.core.record.Recorder; +import org.autojs.autojs.core.shizuku.IUserService; import org.autojs.autojs.model.explorer.ExplorerDirPage; import org.autojs.autojs.model.explorer.ExplorerPage; import org.autojs.autojs.model.explorer.Explorers; @@ -414,9 +415,12 @@ public class CircularMenu implements LayoutInspector.CaptureAvailableListener { private String getCurrentPackage() { if (WrappedShizuku.INSTANCE.isOperational()) { try { - mCurrentPackage = Objects.requireNonNull(WrappedShizuku.service).currentPackage(); - if (!TextUtils.isEmpty(mCurrentPackage)) { - return mCurrentPackage; + IUserService service = WrappedShizuku.getServiceOrNull(); + if (service != null) { + mCurrentPackage = service.currentPackage(); + if (!TextUtils.isEmpty(mCurrentPackage)) { + return mCurrentPackage; + } } } catch (RemoteException ignored) { /* Ignored. */ @@ -439,9 +443,12 @@ public class CircularMenu implements LayoutInspector.CaptureAvailableListener { private String getCurrentActivity() { if (WrappedShizuku.INSTANCE.isOperational()) { try { - mCurrentActivity = Objects.requireNonNull(WrappedShizuku.service).currentActivity(); - if (!TextUtils.isEmpty(mCurrentActivity)) { - return mCurrentActivity; + IUserService service = WrappedShizuku.getServiceOrNull(); + if (service != null) { + mCurrentActivity = service.currentActivity(); + if (!TextUtils.isEmpty(mCurrentActivity)) { + return mCurrentActivity; + } } } catch (RemoteException ignored) { /* Ignored. */ diff --git a/version.properties b/version.properties index 9dcac162..0cf870c4 100644 --- a/version.properties +++ b/version.properties @@ -1,5 +1,5 @@ -#Sat Jan 31 15:04:03 CST 2026 -BUILD_TIME=1769843043403 +#Sat Jan 31 18:47:47 CST 2026 +BUILD_TIME=1769856467115 COMPILE_SDK_VERSION=36 IMAGE_QUANT_CMAKE_VERSION=3.22.1 IMAGE_QUANT_NDK_VERSION=26.1.10909125 @@ -27,6 +27,6 @@ RAPID_OCR_OPENCV_MOBILE_LABEL_VERSION=13 RAPID_OCR_OPENCV_MOBILE_VERSION=4.5.3 TARGET_SDK_VERSION=36 TARGET_SDK_VERSION_INRT=29 -VERSION_BUILD=3678 +VERSION_BUILD=3679 VERSION_NAME=6.7.0 Alpha19 VSCODE_EXT_REQUIRED_VERSION=1.0.13