From 517872f620d3c305b01f775c617e2dc3054a8d1c Mon Sep 17 00:00:00 2001 From: SuperMonster003 Date: Mon, 29 Dec 2025 22:29:57 +0800 Subject: [PATCH] =?UTF-8?q?6.7.0=20-=20Alpha13=20-=20=E4=BF=AE=E5=A4=8D=20?= =?UTF-8?q?auto.registerEvent=20=E6=B3=A8=E5=86=8C=E7=9A=84=E6=97=A0?= =?UTF-8?q?=E9=9A=9C=E7=A2=8D=E6=9C=8D=E5=8A=A1=E4=BA=8B=E4=BB=B6=E4=BC=9A?= =?UTF-8?q?=E8=A2=AB=E5=85=B6=E4=BB=96=E8=84=9A=E6=9C=AC=E8=AF=AF=E6=B8=85?= =?UTF-8?q?=E7=90=86=E7=9A=84=E9=97=AE=E9=A2=98=20(issue=20#466)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changelog/lang_zh-Hans.json | 1 + .../accessibility/AccessibilityService.kt | 82 +++++++++++++------ .../accessibility/SimpleActionAutomator.kt | 22 ++++- .../autojs/autojs/runtime/ScriptRuntime.kt | 14 +++- version.properties | 6 +- 5 files changed, 93 insertions(+), 32 deletions(-) diff --git a/.changelog/lang_zh-Hans.json b/.changelog/lang_zh-Hans.json index e5372fe0..0c1f0fac 100644 --- a/.changelog/lang_zh-Hans.json +++ b/.changelog/lang_zh-Hans.json @@ -56,6 +56,7 @@ "images 部分相关方法可能引发内存泄露的问题 _[`issue #372`](http://issues.autojs6.com/372)_", "ocr 部分重载方法可能无法正常使用的问题", "ocr.detect 方法获得的结果可能与 ocr.mode 不匹配的问题 _[`issue #468`](http://issues.autojs6.com/468)_", + "auto.registerEvent 注册的无障碍服务事件会被其他脚本误清理的问题 _[`issue #466`](http://issues.autojs6.com/466)_", "Android 10 UiObject#child 方法可能出现 ArrayIndexOutOfBoundsException 异常的问题 _[`issue #416`](http://issues.autojs6.com/416)_", "运行项目时 project.json 配置参数无法正常解析的问题", "项目配置文件中构建版本号或构建时间出现较大数字时可能导致应用崩溃的问题", diff --git a/app/src/main/java/org/autojs/autojs/core/accessibility/AccessibilityService.kt b/app/src/main/java/org/autojs/autojs/core/accessibility/AccessibilityService.kt index 7c70edc7..72f5b9b8 100644 --- a/app/src/main/java/org/autojs/autojs/core/accessibility/AccessibilityService.kt +++ b/app/src/main/java/org/autojs/autojs/core/accessibility/AccessibilityService.kt @@ -9,11 +9,11 @@ import android.view.accessibility.AccessibilityNodeInfo import org.autojs.autojs.core.accessibility.AccessibilityTool.Companion.DEFAULT_A11Y_SERVICE_START_TIMEOUT import org.autojs.autojs.core.accessibility.SimpleActionAutomator.Companion.AccessibilityEventCallback import org.autojs.autojs.core.automator.AccessibilityEventWrapper -import org.autojs.autojs.event.EventDispatcher import org.autojs.autojs.core.pref.Language +import org.autojs.autojs.event.EventDispatcher import org.autojs.autojs.ui.main.drawer.DrawerFragment.Companion.Event.AccessibilityServiceStateChangedEvent import org.greenrobot.eventbus.EventBus -import java.util.TreeMap +import java.util.* import java.util.concurrent.ExecutorService import java.util.concurrent.Executors import java.util.concurrent.TimeUnit @@ -21,7 +21,7 @@ import java.util.concurrent.locks.ReentrantLock /** * Created by Stardust on May 2, 2017. - * Modified by SuperMonster003 as of Mar 20, 2022. + * Modified by SuperMonster003 as of Dec 29, 2025. */ open class AccessibilityService : android.accessibilityservice.AccessibilityService() { @@ -30,7 +30,9 @@ open class AccessibilityService : android.accessibilityservice.AccessibilityServ var fastRootInActiveWindow: AccessibilityNodeInfo? = null var bridge: AccessibilityBridge? = null - private val eventBox = TreeMap() + // eventType -> (ownerId -> callback) + private val eventBox = HashMap>() + private val eventBoxLock = Any() private val gestureEventDispatcher = EventDispatcher() @@ -43,23 +45,62 @@ open class AccessibilityService : android.accessibilityservice.AccessibilityServ AccessibilityEvent::class.java.getField( "TYPE_${event.uppercase(Language.getPrefLanguage().locale)}" ).get(null) as Int - } catch (unused: NoSuchFieldException) { + } catch (_: NoSuchFieldException) { throw IllegalArgumentException("Unknown event: $event") } } - fun addAccessibilityEventCallback(name: String, callback: AccessibilityEventCallback?) { - eventBox[eventNameToType(name)] = callback + fun addAccessibilityEventCallback(ownerId: String, name: String, callback: AccessibilityEventCallback?) { + val type = eventNameToType(name) + synchronized(eventBoxLock) { + val bucket = eventBox.getOrPut(type) { HashMap() } + if (callback == null) { + bucket.remove(ownerId) + if (bucket.isEmpty()) eventBox.remove(type) + } else { + bucket[ownerId] = callback + } + } } - fun removeAccessibilityEventCallback(name: String) { - eventBox.remove(eventNameToType(name)) + fun removeAccessibilityEventCallback(ownerId: String, name: String) { + val type = eventNameToType(name) + synchronized(eventBoxLock) { + val bucket = eventBox[type] ?: return + bucket.remove(ownerId) + if (bucket.isEmpty()) eventBox.remove(type) + } + } + + fun removeAllAccessibilityEventCallbacks(ownerId: String) { + synchronized(eventBoxLock) { + val it = eventBox.entries.iterator() + while (it.hasNext()) { + val entry = it.next() + entry.value.remove(ownerId) + if (entry.value.isEmpty()) it.remove() + } + } } override fun onAccessibilityEvent(event: AccessibilityEvent) { instance = this val type = event.eventType - eventBox[type]?.onAccessibilityEvent(AccessibilityEventWrapper(event)) + + // Snapshot callbacks to avoid holding lock while invoking user code. + // zh-CN: 为回调建立快照, 以避免在调用用户代码时持锁. + val callbacks: List = synchronized(eventBoxLock) { + val bucket = eventBox[type] ?: return@synchronized emptyList() + bucket.values.filterNotNull().toList() + } + + if (callbacks.isNotEmpty()) { + val wrapper = AccessibilityEventWrapper(event) + callbacks.forEach { cb -> + cb.onAccessibilityEvent(wrapper) + } + } + if (containsAllEventTypes || eventTypes.contains(type)) { if (type == TYPE_WINDOW_STATE_CHANGED || type == TYPE_VIEW_FOCUSED) { rootInActiveWindow?.also { fastRootInActiveWindow = it } @@ -67,11 +108,9 @@ open class AccessibilityService : android.accessibilityservice.AccessibilityServ for ((_, delegate) in delegates) { val types = delegate.eventTypes if (types == null || types.contains(type)) { - // val start = System.currentTimeMillis() if (delegate.onAccessibilityEvent(this@AccessibilityService, event)) { break } - // Log.v(TAG, "millis: " + (System.currentTimeMillis() - start) + " delegate: " + delegate::class.java.name) } } } @@ -101,11 +140,7 @@ open class AccessibilityService : android.accessibilityservice.AccessibilityServ } override fun getRootInActiveWindow(): AccessibilityNodeInfo? { - return try { - super.getRootInActiveWindow() - } catch (e: Exception) { - null - } + return runCatching { super.getRootInActiveWindow() }.getOrNull() } override fun onDestroy() { @@ -177,13 +212,10 @@ open class AccessibilityService : android.accessibilityservice.AccessibilityServ } } - fun stop() = try { + fun stop() = runCatching { instance?.disableSelf() instance = null - true - } catch (e: Exception) { - false - } + }.isSuccess fun waitForStarted(timeout: Long = DEFAULT_A11Y_SERVICE_START_TIMEOUT): Boolean { if (hasInstance()) { @@ -209,7 +241,11 @@ open class AccessibilityService : android.accessibilityservice.AccessibilityServ @JvmStatic fun clearAccessibilityEventCallback() { - instance?.eventBox?.clear() + instance?.let { svc -> + synchronized(svc.eventBoxLock) { + svc.eventBox.clear() + } + } } fun setCallback(listener: AccessibilityServiceCallback?) { diff --git a/app/src/main/java/org/autojs/autojs/core/accessibility/SimpleActionAutomator.kt b/app/src/main/java/org/autojs/autojs/core/accessibility/SimpleActionAutomator.kt index 393fb424..98a3139d 100644 --- a/app/src/main/java/org/autojs/autojs/core/accessibility/SimpleActionAutomator.kt +++ b/app/src/main/java/org/autojs/autojs/core/accessibility/SimpleActionAutomator.kt @@ -34,9 +34,12 @@ import android.accessibilityservice.AccessibilityService as AndroidAccessibility /** * Created by Stardust on Apr 2, 2017. + * Modified by SuperMonster003 as of Dec 29, 2025. */ class SimpleActionAutomator(private val accessibilityBridge: AccessibilityBridge, private val scriptRuntime: ScriptRuntime) { + private val mA11yEventOwnerId: String = scriptRuntime.ownerId + private val mGlobalActionAutomatorRaw by lazy { GlobalActionAutomator(scriptRuntime.uiHandler.applicationContext, Handler(scriptRuntime.loopers.servantLooper)) { ensureService() @@ -198,12 +201,27 @@ class SimpleActionAutomator(private val accessibilityBridge: AccessibilityBridge // ! zh-CN: 参考 Auto.js Pro. fun registerEvent(eventName: String, callback: AccessibilityEventCallback?) { ensureService() - AccessibilityService.instance?.addAccessibilityEventCallback(eventName, callback) + val service = AccessibilityService.instance ?: return + + if (callback == null) { + service.removeAccessibilityEventCallback(mA11yEventOwnerId, eventName) + return + } + service.addAccessibilityEventCallback(mA11yEventOwnerId, eventName, callback) } // @Created by 抠脚本人 on Jul 10, 2023. fun removeEvent(eventName: String) { - AccessibilityService.instance?.removeAccessibilityEventCallback(eventName) + AccessibilityService.instance?.removeAccessibilityEventCallback(mA11yEventOwnerId, eventName) + } + + /** + * Called when the script exits, only clears accessibility + * event listeners registered by the current script. + * zh-CN: 脚本退出时调用, 只清理由当前脚本注册的无障碍事件监听. + */ + fun removeAllEventsForThisRuntime() { + AccessibilityService.instance?.removeAllAccessibilityEventCallbacks(mA11yEventOwnerId) } private fun performAction(simpleAction: SimpleAction): Boolean { diff --git a/app/src/main/java/org/autojs/autojs/runtime/ScriptRuntime.kt b/app/src/main/java/org/autojs/autojs/runtime/ScriptRuntime.kt index d323aba8..2997ab3c 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/ScriptRuntime.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/ScriptRuntime.kt @@ -11,7 +11,6 @@ import org.autojs.autojs.annotation.ScriptInterface import org.autojs.autojs.annotation.ScriptVariable import org.autojs.autojs.concurrent.VolatileDispose import org.autojs.autojs.core.accessibility.AccessibilityBridge -import org.autojs.autojs.core.accessibility.AccessibilityService import org.autojs.autojs.core.accessibility.SimpleActionAutomator import org.autojs.autojs.core.accessibility.monitor.CloseableManager import org.autojs.autojs.core.activity.ActivityInfoProvider @@ -177,8 +176,8 @@ import org.autojs.autojs.runtime.api.augment.util.VersionCodes as UtilVersionCod /** * Created by Stardust on Jan 27, 2017. - * Modified by SuperMonster003 as of Dec 1, 2021. - * Created by SuperMonster003 on May 24, 2024. + * Modified by SuperMonster003 as of Dec 29, 2025. + * Transformed by SuperMonster003 on May 24, 2024. */ @Suppress("unused", "PropertyName", "PrivatePropertyName") class ScriptRuntime private constructor(builder: Builder) { @@ -186,6 +185,8 @@ class ScriptRuntime private constructor(builder: Builder) { private val mJob = SupervisorJob() val coroutineScope = CoroutineScope(Dispatchers.Default + mJob) val coroutineContext = coroutineScope.coroutineContext + + val ownerId = "runtime@${System.identityHashCode(this)}" private var mUiHandlerAppContext: Context private var mRootShell: AbstractShell? = null @@ -601,7 +602,12 @@ class ScriptRuntime private constructor(builder: Builder) { // ! 清空无障碍事件. // ! en-US (translated by SuperMonster003 on Jul 29, 2024): // ! To clear accessibility event callbacks. - ignoresException({ AccessibilityService.clearAccessibilityEventCallback() }) + // @Hint by SuperMonster003 on Dec 29, 2025. + // ! Only clean up accessibility event callbacks registered + // ! by the current script to avoid affecting other still-running scripts. + // ! zh-CN: 只清理当前脚本注册的无障碍事件回调,避免影响其他仍在运行的脚本. + // # ignoresException({ AccessibilityService.clearAccessibilityEventCallback() }) + ignoresException({ automator.removeAllEventsForThisRuntime() }) ignoresException({ RootUtils.resetRuntimeOverriddenRootModeState() }) diff --git a/version.properties b/version.properties index 244f6f16..1d4bdece 100644 --- a/version.properties +++ b/version.properties @@ -1,5 +1,5 @@ -#Mon Dec 29 18:48:41 CST 2025 -BUILD_TIME=1767005321663 +#Mon Dec 29 19:40:59 CST 2025 +BUILD_TIME=1767008459948 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=3561 +VERSION_BUILD=3562 VERSION_NAME=6.7.0 Alpha13 VSCODE_EXT_REQUIRED_VERSION=1.0.8