GIT 提交信息:
改善无障碍服务应用的跟踪和反馈 - 实现通过应用程序包名跟踪当前活动应用的支持。 - 引入重试机制,提高检测并返回目标应用的可靠性。 - 通过吐司消息增强用户体验,以反馈应用启动问题。
This commit is contained in:
parent
56c14fe3ca
commit
77579d2b5f
|
@ -4,10 +4,14 @@ import android.accessibilityservice.AccessibilityService
|
|||
import android.content.Intent
|
||||
import android.graphics.Rect
|
||||
import android.os.Binder
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import android.view.accessibility.AccessibilityEvent
|
||||
import android.view.accessibility.AccessibilityNodeInfo
|
||||
import android.widget.Toast
|
||||
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
|
||||
import kotlinx.coroutines.delay
|
||||
import java.util.LinkedList
|
||||
|
||||
class MyAccessibilityService : AccessibilityService() {
|
||||
|
@ -22,6 +26,7 @@ class MyAccessibilityService : AccessibilityService() {
|
|||
}
|
||||
|
||||
private val binder = MyBinder()
|
||||
private var targetAppPackageName: String? = null // 目标应用的包名
|
||||
|
||||
inner class MyBinder : Binder() {
|
||||
fun getService(): MyAccessibilityService = this@MyAccessibilityService
|
||||
|
@ -136,6 +141,10 @@ class MyAccessibilityService : AccessibilityService() {
|
|||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找并启动指定应用
|
||||
* @param appName 应用名称
|
||||
*/
|
||||
/**
|
||||
* 查找并启动指定应用
|
||||
* @param appName 应用名称
|
||||
|
@ -160,6 +169,16 @@ class MyAccessibilityService : AccessibilityService() {
|
|||
matchingNodes.firstOrNull()?.let { targetNode ->
|
||||
if (targetNode.performAction(AccessibilityNodeInfo.ACTION_CLICK)) {
|
||||
Log.d(TAG, "Successfully launched: $appName")
|
||||
|
||||
// 启动重试机制
|
||||
retryToDetectTargetApp(10, 3000) { success ->
|
||||
if (success) {
|
||||
Log.d(TAG, "Target app package name detected: $targetAppPackageName")
|
||||
} else {
|
||||
Log.e(TAG, "Failed to detect target app after 10 retries")
|
||||
showToast("Failed to launch $appName")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "Failed to click app: $appName")
|
||||
}
|
||||
|
@ -174,6 +193,49 @@ class MyAccessibilityService : AccessibilityService() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重试检测目标应用
|
||||
* @param maxRetries 最大重试次数
|
||||
* @param delayMillis 每次重试的延时(毫秒)
|
||||
* @param onResult 结果回调,true 表示成功,false 表示失败
|
||||
*/
|
||||
private fun retryToDetectTargetApp(maxRetries: Int, delayMillis: Long, onResult: (Boolean) -> Unit) {
|
||||
var retryCount = 0
|
||||
|
||||
val retryRunnable = object : Runnable {
|
||||
override fun run() {
|
||||
rootInActiveWindow?.let { currentRoot ->
|
||||
val packageName = currentRoot.packageName?.toString()
|
||||
if (packageName != null && packageName != targetAppPackageName) {
|
||||
targetAppPackageName = packageName
|
||||
onResult(true) // 成功检测到目标应用
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
retryCount++
|
||||
if (retryCount < maxRetries) {
|
||||
Handler(Looper.getMainLooper()).postDelayed(this, delayMillis) // 继续重试
|
||||
} else {
|
||||
onResult(false) // 重试次数用尽,失败
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 启动第一次重试
|
||||
Handler(Looper.getMainLooper()).postDelayed(retryRunnable, delayMillis)
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示 Toast 消息
|
||||
* @param message 要显示的消息
|
||||
*/
|
||||
private fun showToast(message: String) {
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理无障碍事件
|
||||
* @param event 无障碍事件
|
||||
|
@ -183,10 +245,63 @@ class MyAccessibilityService : AccessibilityService() {
|
|||
when (event.eventType) {
|
||||
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED -> {
|
||||
Log.d(TAG, "Window state changed: ${event.packageName}")
|
||||
Log.d(TAG, "target app package name: $targetAppPackageName")
|
||||
// 检测当前活动的应用是否发生了变化
|
||||
event.packageName?.let { currentPackageName ->
|
||||
if (targetAppPackageName != null && currentPackageName != targetAppPackageName) {
|
||||
Log.d(TAG, "Detected app switch from $targetAppPackageName to $currentPackageName")
|
||||
retryBackToTargetApp(10, 1000) { success ->
|
||||
if (success) {
|
||||
Log.d(TAG, "Successfully returned to $targetAppPackageName")
|
||||
} else {
|
||||
Log.e(TAG, "Failed to return to $targetAppPackageName after 10 retries")
|
||||
showToast("Failed to return to target app")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重试返回目标应用
|
||||
* @param maxRetries 最大重试次数
|
||||
* @param delayMillis 每次重试的延时(毫秒)
|
||||
* @param onResult 结果回调,true 表示成功,false 表示失败
|
||||
*/
|
||||
private fun retryBackToTargetApp(maxRetries: Int, delayMillis: Long, onResult: (Boolean) -> Unit) {
|
||||
var retryCount = 0
|
||||
|
||||
val retryRunnable = object : Runnable {
|
||||
override fun run() {
|
||||
// 检测当前窗口是否已经返回到目标应用
|
||||
rootInActiveWindow?.let { currentRoot ->
|
||||
val packageName = currentRoot.packageName?.toString()
|
||||
if (packageName == targetAppPackageName) {
|
||||
onResult(true) // 成功返回到目标应用
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试点击返回按钮
|
||||
performGlobalAction(GLOBAL_ACTION_BACK)
|
||||
Log.d(TAG, "Performed back action, retry count: $retryCount")
|
||||
|
||||
retryCount++
|
||||
if (retryCount < maxRetries) {
|
||||
Handler(Looper.getMainLooper()).postDelayed(this, delayMillis) // 继续重试
|
||||
} else {
|
||||
onResult(false) // 重试次数用尽,失败
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 启动第一次重试
|
||||
Handler(Looper.getMainLooper()).postDelayed(retryRunnable, delayMillis)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 安全启动主Activity
|
||||
*/
|
||||
|
@ -206,6 +321,7 @@ class MyAccessibilityService : AccessibilityService() {
|
|||
*/
|
||||
private fun cleanUpResources() {
|
||||
instance = null
|
||||
targetAppPackageName = null
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue
Block a user