6.7.0 - Alpha13 - 新增 auto.state 属性 (getter) 及 shizuku.state 属性 (getter)

This commit is contained in:
SuperMonster003
2026-01-08 16:32:00 +08:00
parent 1d89e40486
commit ea29d83a3f
13 changed files with 184 additions and 49 deletions

View File

@@ -1,7 +1,7 @@
{ {
"$data": { "$data": {
"v6.7.0": { "v6.7.0": {
"released_date": "2026/01/06", "released_date": "2026/01/08",
"feature": [ "feature": [
"插件中心功能, 支持插件的安装/卸载/更新等操作 (入口: 主页抽屉按钮)", "插件中心功能, 支持插件的安装/卸载/更新等操作 (入口: 主页抽屉按钮)",
"cvt 模块, 用于数据单位转换 (参阅 项目文档 > [单位转换](https://docs.autojs6.com/#/cvt))", "cvt 模块, 用于数据单位转换 (参阅 项目文档 > [单位转换](https://docs.autojs6.com/#/cvt))",
@@ -19,6 +19,7 @@
"http 模块请求相关方法支持缓存控制选项参数 (cacheBody/bodyCacheThresholdBytes)", "http 模块请求相关方法支持缓存控制选项参数 (cacheBody/bodyCacheThresholdBytes)",
"http 模块请求相关方法支持不安全选项参数 (isInsecure/insecure), 用于忽略证书相关异常 _[`issue #417`](http://issues.autojs6.com/417)_", "http 模块请求相关方法支持不安全选项参数 (isInsecure/insecure), 用于忽略证书相关异常 _[`issue #417`](http://issues.autojs6.com/417)_",
"http 模块请求相关方法支持 options.client 选项, 用于配置 OkHttpClient.Builder (如 followRedirects 等) _[`issue #454`](http://issues.autojs6.com/454)_", "http 模块请求相关方法支持 options.client 选项, 用于配置 OkHttpClient.Builder (如 followRedirects 等) _[`issue #454`](http://issues.autojs6.com/454)_",
"auto.state 属性 (getter) 及 shizuku.state 属性 (getter), 用于获取无障碍服务状态及 Shizuku 服务状态",
"runtime.(set/is)JavaPrimitiveWrap 方法, 用于设置或获取 Java 原始类型包装策略 _[`issue #435`](http://issues.autojs6.com/435)_", "runtime.(set/is)JavaPrimitiveWrap 方法, 用于设置或获取 Java 原始类型包装策略 _[`issue #435`](http://issues.autojs6.com/435)_",
"autojs.(restart/exit) 方法, 用于重启或退出 AutoJs6 应用, 并支持应用重启时自动运行其参数指定的脚本 _[`issue #460`](http://issues.autojs6.com/460)_", "autojs.(restart/exit) 方法, 用于重启或退出 AutoJs6 应用, 并支持应用重启时自动运行其参数指定的脚本 _[`issue #460`](http://issues.autojs6.com/460)_",
"UiObject#isShifted 方法, 用于检测控件位置变化 _[`issue #469`](http://issues.autojs6.com/469)_", "UiObject#isShifted 方法, 用于检测控件位置变化 _[`issue #469`](http://issues.autojs6.com/469)_",

View File

@@ -22,7 +22,7 @@ public class AccessibilityBridgeImpl extends AccessibilityBridge {
@Override @Override
public void ensureServiceStarted(boolean isForcibleRestart) { public void ensureServiceStarted(boolean isForcibleRestart) {
if (isForcibleRestart && mA11yTool.serviceExists()) { if (isForcibleRestart && mA11yTool.hasService()) {
mA11yTool.stopService(true); mA11yTool.stopService(true);
Log.d(TAG, "isForcibleRestart"); Log.d(TAG, "isForcibleRestart");
} }

View File

@@ -21,7 +21,7 @@ import java.util.concurrent.locks.ReentrantLock
/** /**
* Created by Stardust on May 2, 2017. * Created by Stardust on May 2, 2017.
* Modified by SuperMonster003 as of Dec 29, 2025. * Modified by SuperMonster003 as of Jan 7, 2026.
*/ */
open class AccessibilityService : android.accessibilityservice.AccessibilityService() { open class AccessibilityService : android.accessibilityservice.AccessibilityService() {
@@ -87,6 +87,10 @@ open class AccessibilityService : android.accessibilityservice.AccessibilityServ
instance = this instance = this
val type = event.eventType val type = event.eventType
// Mark service as operational when we receive the first accessibility event.
// zh-CN: 当收到首个无障碍事件时, 将服务标记为可工作状态.
markOperationalStateIfNeeded()
// Snapshot callbacks to avoid holding lock while invoking user code. // Snapshot callbacks to avoid holding lock while invoking user code.
// zh-CN: 为回调建立快照, 以避免在调用用户代码时持锁. // zh-CN: 为回调建立快照, 以避免在调用用户代码时持锁.
val callbacks: List<AccessibilityEventCallback> = synchronized(eventBoxLock) { val callbacks: List<AccessibilityEventCallback> = synchronized(eventBoxLock) {
@@ -149,6 +153,8 @@ open class AccessibilityService : android.accessibilityservice.AccessibilityServ
instance = null instance = null
bridge = null bridge = null
resetOperationalState()
mEventExecutor?.shutdownNow() mEventExecutor?.shutdownNow()
callback?.onDisconnected() callback?.onDisconnected()
EventBus.getDefault().post(object : AccessibilityServiceStateChangedEvent {}) EventBus.getDefault().post(object : AccessibilityServiceStateChangedEvent {})
@@ -183,8 +189,13 @@ open class AccessibilityService : android.accessibilityservice.AccessibilityServ
private val LOCK = ReentrantLock() private val LOCK = ReentrantLock()
private val ENABLED = LOCK.newCondition() private val ENABLED = LOCK.newCondition()
private val OPERATIONAL = LOCK.newCondition()
private var callback: AccessibilityServiceCallback? = null private var callback: AccessibilityServiceCallback? = null
@Volatile
var hasOperationalState = false
var instance: AccessibilityService? = null var instance: AccessibilityService? = null
private set private set
@@ -198,6 +209,27 @@ open class AccessibilityService : android.accessibilityservice.AccessibilityServ
fun hasInstance() = instance != null fun hasInstance() = instance != null
private fun markOperationalStateIfNeeded() {
if (hasOperationalState) return
LOCK.lock()
try {
if (hasOperationalState) return
hasOperationalState = true
OPERATIONAL.signalAll()
} finally {
LOCK.unlock()
}
}
private fun resetOperationalState() {
LOCK.lock()
try {
hasOperationalState = false
} finally {
LOCK.unlock()
}
}
fun addDelegate(uniquePriority: Int, delegate: AccessibilityDelegate) { fun addDelegate(uniquePriority: Int, delegate: AccessibilityDelegate) {
// @Hint by 抠脚本人 (https://github.com/little-alei) on Jul 10, 2023. // @Hint by 抠脚本人 (https://github.com/little-alei) on Jul 10, 2023.
// ! 用于记录 eventTypes 中的事件 id. // ! 用于记录 eventTypes 中的事件 id.
@@ -239,6 +271,30 @@ open class AccessibilityService : android.accessibilityservice.AccessibilityServ
} }
} }
// Wait until the service becomes operational (not only connected).
// zh-CN: 等待服务进入可工作状态 (不只是已连接).
fun waitForOperational(timeout: Long = DEFAULT_A11Y_SERVICE_START_TIMEOUT): Boolean {
if (hasInstance() && hasOperationalState) {
return true
}
LOCK.lock()
try {
if (hasInstance() && hasOperationalState) {
return true
}
if (timeout == -1L) {
OPERATIONAL.await()
return true
}
return OPERATIONAL.await(timeout, TimeUnit.MILLISECONDS)
} catch (e: InterruptedException) {
e.printStackTrace()
return false
} finally {
LOCK.unlock()
}
}
@JvmStatic @JvmStatic
fun clearAccessibilityEventCallback() { fun clearAccessibilityEventCallback() {
instance?.let { svc -> instance?.let { svc ->

View File

@@ -48,7 +48,7 @@ class AccessibilityTool(private val context: Context? = null) {
} }
try { try {
mApplicationContext.startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)) mApplicationContext.startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
} catch (e: ActivityNotFoundException) { } catch (_: ActivityNotFoundException) {
ViewUtils.showToast(mContext, R.string.go_to_accessibility_settings, true) ViewUtils.showToast(mContext, R.string.go_to_accessibility_settings, true)
} }
} }
@@ -60,20 +60,27 @@ class AccessibilityTool(private val context: Context? = null) {
else -> emptyArray() else -> emptyArray()
} }
@ScriptInterface
fun isServiceRunning() = hasInstance() && serviceExists()
@ScriptInterface @ScriptInterface
fun hasInstance() = AccessibilityService.hasInstance() fun hasInstance() = AccessibilityService.hasInstance()
// Means the service is enabled in system settings.
// zh-CN: 表示服务在系统设置中处于已启用状态.
@ScriptInterface @ScriptInterface
fun serviceExists(): Boolean { fun hasService(): Boolean {
val services = Secure.getString( val services = Secure.getString(
mApplicationContext.contentResolver, Secure.ENABLED_ACCESSIBILITY_SERVICES mApplicationContext.contentResolver, Secure.ENABLED_ACCESSIBILITY_SERVICES
) ?: return false ) ?: return false
return services.split(SERVICES_DELIMITER).any { it.trim() == mServiceName } return services.split(SERVICES_DELIMITER).any { it.trim() == mServiceName }
} }
@ScriptInterface
fun isRunning() = hasService() && hasInstance()
// Means the service is enabled and confirmed workable in current process.
// zh-CN: 表示服务已启用, 且在当前进程中已确认可用.
@ScriptInterface
fun isOperational() = isRunning() && AccessibilityService.hasOperationalState
@JvmOverloads @JvmOverloads
@ScriptInterface @ScriptInterface
fun startService(withLaunchSettings: Boolean = true): Boolean { fun startService(withLaunchSettings: Boolean = true): Boolean {
@@ -81,7 +88,7 @@ class AccessibilityTool(private val context: Context? = null) {
if (startServiceWithConvenientWaysIfPossible()) { if (startServiceWithConvenientWaysIfPossible()) {
result = true.also { Log.d(TAG, "Accessibility service enabled successfully by a certain \"convenient way\"") } result = true.also { Log.d(TAG, "Accessibility service enabled successfully by a certain \"convenient way\"") }
} }
if (isServiceRunning()) { if (isRunning()) {
result = true.also { Log.d(TAG, "Accessibility service is running") } result = true.also { Log.d(TAG, "Accessibility service is running") }
} }
return result || false.also { if (withLaunchSettings) launchSettings() } return result || false.also { if (withLaunchSettings) launchSettings() }
@@ -102,7 +109,7 @@ class AccessibilityTool(private val context: Context? = null) {
} }
if (!result) { if (!result) {
if (AccessibilityService.stop() && !serviceExists()) { if (AccessibilityService.stop() && !hasService()) {
result = true.also { Log.d(TAG, "Accessibility service disabled successfully by \"disableSelf\"") } result = true.also { Log.d(TAG, "Accessibility service disabled successfully by \"disableSelf\"") }
} }
} }
@@ -122,7 +129,7 @@ class AccessibilityTool(private val context: Context? = null) {
@JvmOverloads @JvmOverloads
@ScriptInterface @ScriptInterface
fun startServiceAndWaitFor(timeout: Long = DEFAULT_A11Y_SERVICE_START_TIMEOUT) { fun startServiceAndWaitFor(timeout: Long = DEFAULT_A11Y_SERVICE_START_TIMEOUT) {
if (isServiceRunning()) return if (isRunning()) return
if (startServiceWithConvenientWaysIfPossibleAndWaitFor()) return if (startServiceWithConvenientWaysIfPossibleAndWaitFor()) return
launchSettings() launchSettings()
if (!AccessibilityService.waitForStarted(timeout)) { if (!AccessibilityService.waitForStarted(timeout)) {
@@ -130,6 +137,23 @@ class AccessibilityTool(private val context: Context? = null) {
} }
} }
// Start service and wait until it becomes operational.
// zh-CN: 启动服务并等待其进入可工作状态.
@JvmOverloads
@ScriptInterface
fun startServiceAndWaitForOperational(timeout: Long = DEFAULT_A11Y_SERVICE_START_TIMEOUT) {
if (isOperational()) return
if (startServiceWithConvenientWaysIfPossibleAndWaitFor(timeout)) {
AccessibilityService.waitForOperational(timeout)
if (isOperational()) return
} else {
launchSettings()
}
if (!AccessibilityService.waitForOperational(timeout)) {
throw ScriptInterruptedException()
}
}
private fun startServiceWithConvenientWaysIfPossible() = when { private fun startServiceWithConvenientWaysIfPossible() = when {
startServiceWithRootIfPossible() -> true startServiceWithRootIfPossible() -> true
startServiceWithSecureIfPossible() -> true startServiceWithSecureIfPossible() -> true
@@ -144,12 +168,26 @@ class AccessibilityTool(private val context: Context? = null) {
@ScriptInterface @ScriptInterface
fun ensureService() { fun ensureService() {
if (isServiceRunning()) return if (isRunning()) return
if (startServiceWithConvenientWaysIfPossibleAndWaitFor()) return if (startServiceWithConvenientWaysIfPossibleAndWaitFor()) return
launchSettings() launchSettings()
if (AccessibilityService.waitForStarted()) return if (AccessibilityService.waitForStarted()) return
when { when {
!serviceExists() -> throw ScriptException(mContext.getString(R.string.text_a11y_service_enabled_but_not_running)) !hasService() -> throw ScriptException(mContext.getString(R.string.text_a11y_service_enabled_but_not_running))
else -> throw ScriptException(mContext.getString(R.string.error_no_accessibility_permission))
}
}
// Ensure service is operational, otherwise throw a concrete error.
// zh-CN: 确保服务处于可工作状态, 否则抛出明确的错误信息.
@ScriptInterface
fun ensureServiceOperational(timeout: Long = DEFAULT_A11Y_SERVICE_START_TIMEOUT) {
if (isOperational()) return
startServiceAndWaitForOperational(timeout)
if (isOperational()) return
when {
!hasService() -> throw ScriptException(mContext.getString(R.string.text_a11y_service_enabled_but_not_running))
!hasInstance() -> throw ScriptException(mContext.getString(R.string.text_a11y_service_enabled_but_not_running))
else -> throw ScriptException(mContext.getString(R.string.error_no_accessibility_permission)) else -> throw ScriptException(mContext.getString(R.string.error_no_accessibility_permission))
} }
} }
@@ -159,8 +197,8 @@ class AccessibilityTool(private val context: Context? = null) {
private fun isRootAccessible() = Pref.shouldStartA11yServiceWithRoot() && RootUtils.isRootAvailable() private fun isRootAccessible() = Pref.shouldStartA11yServiceWithRoot() && RootUtils.isRootAvailable()
private fun startServiceWithRoot(timeout: Long? = null): Boolean = when (timeout != null) { private fun startServiceWithRoot(timeout: Long? = null): Boolean = when (timeout != null) {
true -> startServiceWithRoot() && AccessibilityService.waitForStarted(timeout.toLong()) true -> startServiceWithRoot() && AccessibilityService.waitForStarted(timeout)
else -> try { else -> runCatching {
stopServiceWithRoot() stopServiceWithRoot()
val services = getServicesWithRoot(true) val services = getServicesWithRoot(true)
@@ -172,31 +210,27 @@ class AccessibilityTool(private val context: Context? = null) {
val resultState = ProcessShell.execCommand(cmdState, true) val resultState = ProcessShell.execCommand(cmdState, true)
TextUtils.isEmpty(resultServices.error) && TextUtils.isEmpty(resultState.error) TextUtils.isEmpty(resultServices.error) && TextUtils.isEmpty(resultState.error)
} catch (e: Exception) { }.isSuccess
false
}
} }
private fun startServiceWithRootIfPossible(timeout: Long? = null) = isRootAccessible() && startServiceWithRoot(timeout) private fun startServiceWithRootIfPossible(timeout: Long? = null) = isRootAccessible() && startServiceWithRoot(timeout)
private fun startServiceWithSecure(timeout: Long? = null): Boolean = when (timeout != null) { private fun startServiceWithSecure(timeout: Long? = null): Boolean = when (timeout != null) {
true -> startServiceWithSecure() && AccessibilityService.waitForStarted(timeout) true -> startServiceWithSecure() && AccessibilityService.waitForStarted(timeout)
else -> try { else -> runCatching {
stopServiceWithSecure() stopServiceWithSecure()
val services = getServicesWithSecure(true) val services = getServicesWithSecure(true)
Secure.putString(mApplicationContext.contentResolver, Secure.ENABLED_ACCESSIBILITY_SERVICES, services) Secure.putString(mApplicationContext.contentResolver, Secure.ENABLED_ACCESSIBILITY_SERVICES, services)
Secure.putInt(mApplicationContext.contentResolver, Secure.ACCESSIBILITY_ENABLED, 1) Secure.putInt(mApplicationContext.contentResolver, Secure.ACCESSIBILITY_ENABLED, 1)
serviceExists() hasService()
} catch (e: Exception) { }.isSuccess
false
}
} }
private fun startServiceWithSecureIfPossible(timeout: Long? = null) = isSecureAccessible() && startServiceWithSecure(timeout) private fun startServiceWithSecureIfPossible(timeout: Long? = null) = isSecureAccessible() && startServiceWithSecure(timeout)
private fun stopServiceWithRoot() = try { private fun stopServiceWithRoot() = runCatching {
val services = getServicesWithRoot(false) val services = getServicesWithRoot(false)
val cmdServices = "settings put secure enabled_accessibility_services $services" val cmdServices = "settings put secure enabled_accessibility_services $services"
@@ -206,20 +240,16 @@ class AccessibilityTool(private val context: Context? = null) {
val resultState = ProcessShell.execCommand(cmdState, true) val resultState = ProcessShell.execCommand(cmdState, true)
TextUtils.isEmpty(resultServices.error) && TextUtils.isEmpty(resultState.error) TextUtils.isEmpty(resultServices.error) && TextUtils.isEmpty(resultState.error)
} catch (e: Exception) { }.isSuccess
false
}
private fun stopServiceWithSecure() = try { private fun stopServiceWithSecure() = runCatching {
val services = getServicesWithSecure(false) val services = getServicesWithSecure(false)
Secure.putString(mApplicationContext.contentResolver, Secure.ENABLED_ACCESSIBILITY_SERVICES, services) Secure.putString(mApplicationContext.contentResolver, Secure.ENABLED_ACCESSIBILITY_SERVICES, services)
Secure.putInt(mApplicationContext.contentResolver, Secure.ACCESSIBILITY_ENABLED, 0) Secure.putInt(mApplicationContext.contentResolver, Secure.ACCESSIBILITY_ENABLED, 0)
!serviceExists() !hasService()
} catch (e: Exception) { }.isSuccess
false
}
private fun getServicesWithRoot(withAutoJs: Boolean? = null): String = when (withAutoJs) { private fun getServicesWithRoot(withAutoJs: Boolean? = null): String = when (withAutoJs) {
true -> attachAutoJsService(getServicesWithRoot(false)) true -> attachAutoJsService(getServicesWithRoot(false))

View File

@@ -75,7 +75,7 @@ public abstract class LayoutInspectTileService extends TileService implements La
/* Ignored. */ /* Ignored. */
} }
if (mA11yTool.isServiceRunning()) { if (mA11yTool.isRunning()) {
mCapturing = true; mCapturing = true;
captureCurrentWindowDelayed(); captureCurrentWindowDelayed();
} else { } else {

View File

@@ -128,14 +128,17 @@ object WrappedShizuku {
fun isInstalled(context: Context) = getLaunchIntent(context) != null fun isInstalled(context: Context) = getLaunchIntent(context) != null
@ScriptInterface @ScriptInterface
fun hasPermission() = try { fun hasPermission() = runCatching {
Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED Shizuku.checkSelfPermission() == PackageManager.PERMISSION_GRANTED
} catch (e: Throwable) { }.getOrElse { e ->
false.also { if (e.message?.contains(Regex("binder .+n[o']t been received", RegexOption.IGNORE_CASE)) == false) e.printStackTrace() } if (e.message?.contains(Regex("binder .+n[o']t been received", RegexOption.IGNORE_CASE)) == false) {
e.printStackTrace()
}
return@getOrElse false
} }
@ScriptInterface @ScriptInterface
fun isOperational(): Boolean = isRunning() && hasPermission() fun isOperational() = isRunning() && hasPermission()
@ScriptInterface @ScriptInterface
fun isRunning() = mHasBinder fun isRunning() = mHasBinder

View File

@@ -14,6 +14,7 @@ import org.autojs.autojs.extension.ArrayExtensions.toNativeArray
import org.autojs.autojs.extension.FlexibleArray import org.autojs.autojs.extension.FlexibleArray
import org.autojs.autojs.extension.FlexibleArray.Companion.component1 import org.autojs.autojs.extension.FlexibleArray.Companion.component1
import org.autojs.autojs.extension.FlexibleArray.Companion.component2 import org.autojs.autojs.extension.FlexibleArray.Companion.component2
import org.autojs.autojs.extension.ScriptableExtensions.defineProp
import org.autojs.autojs.runtime.ScriptRuntime import org.autojs.autojs.runtime.ScriptRuntime
import org.autojs.autojs.runtime.api.augment.Augmentable import org.autojs.autojs.runtime.api.augment.Augmentable
import org.autojs.autojs.runtime.api.augment.Invokable import org.autojs.autojs.runtime.api.augment.Invokable
@@ -22,6 +23,7 @@ import org.autojs.autojs.runtime.exception.WrappedIllegalArgumentException
import org.autojs.autojs.util.RhinoUtils.UNDEFINED import org.autojs.autojs.util.RhinoUtils.UNDEFINED
import org.autojs.autojs.util.RhinoUtils.callFunction import org.autojs.autojs.util.RhinoUtils.callFunction
import org.autojs.autojs.util.RhinoUtils.newNativeArray import org.autojs.autojs.util.RhinoUtils.newNativeArray
import org.autojs.autojs.util.RhinoUtils.newNativeObject
import org.mozilla.javascript.BaseFunction import org.mozilla.javascript.BaseFunction
import org.mozilla.javascript.Context import org.mozilla.javascript.Context
import org.mozilla.javascript.NativeArray import org.mozilla.javascript.NativeArray
@@ -38,8 +40,11 @@ class Auto(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime
::stop.name, ::stop.name,
::enable.name, ::enable.name,
::disable.name, ::disable.name,
::isRunning.name, ::hasInstance.name,
::hasService.name,
::exists.name, ::exists.name,
::isRunning.name,
::isOperational.name,
::stateListener.name, ::stateListener.name,
::registerEvent.name, ::registerEvent.name,
::registerEvents.name, ::registerEvents.name,
@@ -75,6 +80,14 @@ class Auto(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime
"windowRoots" to Supplier { "windowRoots" to Supplier {
scriptRuntime.accessibilityBridge.windowRoots().map { UiObject.createRoot(it) }.toNativeArray() scriptRuntime.accessibilityBridge.windowRoots().map { UiObject.createRoot(it) }.toNativeArray()
}, },
"state" to Supplier {
newNativeObject().also { o ->
o.defineProp("hasInstance", accessibilityTool.hasInstance())
o.defineProp("hasService", accessibilityTool.hasService())
o.defineProp("isRunning", accessibilityTool.isRunning())
o.defineProp("isOperational", accessibilityTool.isOperational())
}
}
) )
override fun invoke(vararg args: Any?): Any = ensureArgumentsAtMost(args, 2) { override fun invoke(vararg args: Any?): Any = ensureArgumentsAtMost(args, 2) {
@@ -139,14 +152,32 @@ class Auto(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun isRunning(scriptRuntime: ScriptRuntime, args: Array<out Any?>) = ensureArgumentsIsEmpty(args) { fun hasInstance(scriptRuntime: ScriptRuntime, args: Array<out Any?>) = ensureArgumentsIsEmpty(args) {
accessibilityTool.isServiceRunning() accessibilityTool.hasInstance()
}
@JvmStatic
@RhinoRuntimeFunctionInterface
fun hasService(scriptRuntime: ScriptRuntime, args: Array<out Any?>) = ensureArgumentsIsEmpty(args) {
accessibilityTool.hasService()
} }
@JvmStatic @JvmStatic
@RhinoRuntimeFunctionInterface @RhinoRuntimeFunctionInterface
fun exists(scriptRuntime: ScriptRuntime, args: Array<out Any?>) = ensureArgumentsIsEmpty(args) { fun exists(scriptRuntime: ScriptRuntime, args: Array<out Any?>) = ensureArgumentsIsEmpty(args) {
accessibilityTool.serviceExists() accessibilityTool.hasService()
}
@JvmStatic
@RhinoRuntimeFunctionInterface
fun isRunning(scriptRuntime: ScriptRuntime, args: Array<out Any?>) = ensureArgumentsIsEmpty(args) {
accessibilityTool.isRunning()
}
@JvmStatic
@RhinoRuntimeFunctionInterface
fun isOperational(scriptRuntime: ScriptRuntime, args: Array<out Any?>) = ensureArgumentsIsEmpty(args) {
accessibilityTool.isOperational()
} }
@JvmStatic @JvmStatic

View File

@@ -1,6 +1,7 @@
package org.autojs.autojs.runtime.api.augment.shizuku package org.autojs.autojs.runtime.api.augment.shizuku
import org.autojs.autojs.annotation.RhinoRuntimeFunctionInterface import org.autojs.autojs.annotation.RhinoRuntimeFunctionInterface
import org.autojs.autojs.extension.ScriptableExtensions.defineProp
import org.autojs.autojs.runtime.ScriptRuntime import org.autojs.autojs.runtime.ScriptRuntime
import org.autojs.autojs.runtime.api.AbstractShell import org.autojs.autojs.runtime.api.AbstractShell
import org.autojs.autojs.runtime.api.WrappedShizuku import org.autojs.autojs.runtime.api.WrappedShizuku
@@ -8,6 +9,8 @@ import org.autojs.autojs.runtime.api.augment.Augmentable
import org.autojs.autojs.runtime.api.augment.Invokable import org.autojs.autojs.runtime.api.augment.Invokable
import org.autojs.autojs.runtime.api.augment.app.App import org.autojs.autojs.runtime.api.augment.app.App
import org.autojs.autojs.runtime.api.augment.shell.Shell import org.autojs.autojs.runtime.api.augment.shell.Shell
import org.autojs.autojs.util.RhinoUtils.newNativeObject
import java.util.function.Supplier
@Suppress("unused", "UNUSED_PARAMETER") @Suppress("unused", "UNUSED_PARAMETER")
class Shizuku(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), Invokable { class Shizuku(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), Invokable {
@@ -21,6 +24,17 @@ class Shizuku(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRunt
::currentComponent.name, ::currentComponent.name,
) )
override val selfAssignmentGetters = listOf<Pair<String, Supplier<Any?>>>(
"state" to Supplier {
newNativeObject().also { o ->
o.defineProp("isInstalled", WrappedShizuku.isInstalled(globalContext))
o.defineProp("isRunning", WrappedShizuku.isRunning())
o.defineProp("hasPermission", WrappedShizuku.hasPermission())
o.defineProp("isOperational", WrappedShizuku.isOperational())
}
}
)
override fun invoke(vararg args: Any?): AbstractShell.Result = execCommand(scriptRuntime, args) override fun invoke(vararg args: Any?): AbstractShell.Result = execCommand(scriptRuntime, args)
companion object { companion object {

View File

@@ -11,7 +11,7 @@ open class AccessibilityService(final override val context: Context) : ServiceIt
private val mA11yTool = AccessibilityTool(context) private val mA11yTool = AccessibilityTool(context)
override val isRunning override val isRunning
get() = mA11yTool.serviceExists() || mA11yTool.isServiceRunning() get() = mA11yTool.hasService() || mA11yTool.isRunning()
override fun active(): Boolean { override fun active(): Boolean {
return mA11yTool.restartService(true) return mA11yTool.restartService(true)
@@ -44,7 +44,7 @@ open class AccessibilityService(final override val context: Context) : ServiceIt
} }
override fun onToggleSuccess() { override fun onToggleSuccess() {
if (mA11yTool.serviceExists() && !mA11yTool.isServiceRunning()) { if (mA11yTool.hasService() && !mA11yTool.isRunning()) {
ViewUtils.showToast(context, R.string.text_a11y_service_enabled_but_not_running, true) ViewUtils.showToast(context, R.string.text_a11y_service_enabled_but_not_running, true)
} }
super.onToggleSuccess() super.onToggleSuccess()

View File

@@ -64,7 +64,7 @@ abstract class BaseActivity : AppCompatActivity() {
// @Dubious by SuperMonster003 on Oct 28, 2024. // @Dubious by SuperMonster003 on Oct 28, 2024.
// ! Is it property to start a11y service automatically here? // ! Is it property to start a11y service automatically here?
// ! zh-CN: 无障碍服务自启动放在这里是否合适? // ! zh-CN: 无障碍服务自启动放在这里是否合适?
AccessibilityTool(this).apply { if (!isServiceRunning()) startService(false) } AccessibilityTool(this).apply { if (!isRunning()) startService(false) }
} }
private fun setApplicationLocale(context: Context) { private fun setApplicationLocale(context: Context) {

View File

@@ -318,7 +318,7 @@ public class CircularMenu implements LayoutInspector.CaptureAvailableListener {
mLayoutInspectDialog.dismiss(); mLayoutInspectDialog.dismiss();
mLayoutInspectDialog = null; mLayoutInspectDialog = null;
} }
if (!mA11yTool.isServiceRunning()) { if (!mA11yTool.isRunning()) {
if (!mA11yTool.startService(false)) { if (!mA11yTool.startService(false)) {
ViewUtils.showToast(mContext, mContext.getString(R.string.error_no_accessibility_permission_to_capture)); ViewUtils.showToast(mContext, mContext.getString(R.string.error_no_accessibility_permission_to_capture));
mA11yTool.launchSettings(); mA11yTool.launchSettings();

View File

@@ -127,7 +127,7 @@ open class DrawerFragment : Fragment() {
override fun refreshSubtitle(aimState: Boolean) { override fun refreshSubtitle(aimState: Boolean) {
val oldSubtitle = mAccessibilityServiceItem.subtitle val oldSubtitle = mAccessibilityServiceItem.subtitle
if (aimState) { if (aimState) {
if (mA11yTool.serviceExists() && !mA11yTool.isServiceRunning()) { if (mA11yTool.hasService() && !mA11yTool.isRunning()) {
mAccessibilityServiceItem.subtitle = context.getString(R.string.text_malfunctioning) mAccessibilityServiceItem.subtitle = context.getString(R.string.text_malfunctioning)
} else { } else {
mAccessibilityServiceItem.subtitle = null mAccessibilityServiceItem.subtitle = null

View File

@@ -1,5 +1,5 @@
#Tue Jan 06 21:47:58 CST 2026 #Thu Jan 08 01:30:58 CST 2026
BUILD_TIME=1767707278134 BUILD_TIME=1767807058123
COMPILE_SDK_VERSION=36 COMPILE_SDK_VERSION=36
IMAGE_QUANT_CMAKE_VERSION=3.22.1 IMAGE_QUANT_CMAKE_VERSION=3.22.1
IMAGE_QUANT_NDK_VERSION=26.1.10909125 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 RAPID_OCR_OPENCV_MOBILE_VERSION=4.5.3
TARGET_SDK_VERSION=36 TARGET_SDK_VERSION=36
TARGET_SDK_VERSION_INRT=29 TARGET_SDK_VERSION_INRT=29
VERSION_BUILD=3581 VERSION_BUILD=3583
VERSION_NAME=6.7.0 Alpha13 VERSION_NAME=6.7.0 Alpha13
VSCODE_EXT_REQUIRED_VERSION=1.0.8 VSCODE_EXT_REQUIRED_VERSION=1.0.8