From e927c8d0dc1edfc2f65b0832a4b00136b38ebead Mon Sep 17 00:00:00 2001 From: lisonge Date: Fri, 17 Nov 2023 17:37:11 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E8=A7=84=E5=88=99?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/li/songe/gkd/service/AbState.kt | 10 +- .../java/li/songe/gkd/service/GkdAbService.kt | 97 +++++++++++++------ .../main/java/li/songe/gkd/util/SubsState.kt | 4 + 3 files changed, 73 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/li/songe/gkd/service/AbState.kt b/app/src/main/java/li/songe/gkd/service/AbState.kt index bfa10eafd..2369344a6 100644 --- a/app/src/main/java/li/songe/gkd/service/AbState.kt +++ b/app/src/main/java/li/songe/gkd/service/AbState.kt @@ -74,16 +74,14 @@ var activityChangeTime = 0L // null: app 切换过 // true: 需要执行优化(此界面组需要存在开屏广告) // false: 执行优化过了/已经过了优化时间 +@Volatile var openAdOptimized: Boolean? = null const val openAdOptimizedTime = 5000L fun isAvailableRule(rule: Rule): Boolean { val t = System.currentTimeMillis() - if (!rule.isOpenAd && openAdOptimized == true) { - if (t - appChangeTime < openAdOptimizedTime) { - // app 切换一段时间内, 仅开屏广告可使用 - return false - } else { + if (openAdOptimized == true) { + if (t - appChangeTime > openAdOptimizedTime) { openAdOptimized = false } } @@ -146,8 +144,8 @@ fun isAvailableRule(rule: Rule): Boolean { } fun insertClickLog(rule: Rule) { - toastClickTip() rule.trigger() + toastClickTip() appScope.launchTry(Dispatchers.IO) { val clickLog = ClickLog( appId = topActivityFlow.value?.appId, diff --git a/app/src/main/java/li/songe/gkd/service/GkdAbService.kt b/app/src/main/java/li/songe/gkd/service/GkdAbService.kt index eba431625..d5a49cc04 100644 --- a/app/src/main/java/li/songe/gkd/service/GkdAbService.kt +++ b/app/src/main/java/li/songe/gkd/service/GkdAbService.kt @@ -15,10 +15,14 @@ import com.blankj.utilcode.util.ServiceUtils import io.ktor.client.request.get import io.ktor.client.statement.bodyAsText import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.Job +import kotlinx.coroutines.cancel import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import li.songe.gkd.composition.CompositionAbService @@ -44,7 +48,7 @@ import kotlin.coroutines.resume import kotlin.coroutines.suspendCoroutine -@OptIn(FlowPreview::class) +@OptIn(FlowPreview::class, ExperimentalCoroutinesApi::class) class GkdAbService : CompositionAbService({ useLifeCycleLog() @@ -93,12 +97,58 @@ class GkdAbService : CompositionAbService({ var lastTriggerShizukuTime = 0L var lastContentEventTime = 0L var job: Job? = null + val singleThread = Dispatchers.IO.limitedParallelism(1) + onDestroy { + singleThread.cancel() + } + val lastQueryTimeFlow = MutableStateFlow(0L) + val debounceTime = 500L + fun newQueryTask() { + job = scope.launchTry(singleThread) { + val activityRule = getCurrentRules() + for (rule in (activityRule.rules)) { + if (!isActive && !rule.isOpenAd) break + if (!isAvailableRule(rule)) continue + val nodeVal = safeActiveWindow ?: continue + val target = rule.query(nodeVal) ?: continue + if (activityRule !== getCurrentRules()) break + + // 开始 action 延迟 + if (rule.actionDelay > 0 && rule.actionDelayTriggerTime == 0L) { + rule.triggerDelay() + // 防止在 actionDelay 时间内没有事件发送导致无法触发 + scope.launch(singleThread) { + delay(rule.actionDelay - debounceTime) + lastQueryTimeFlow.value = System.currentTimeMillis() + } + continue + } + + // 如果节点在屏幕外部, click 的结果为 null + val actionResult = rule.performAction(context, target) + if (actionResult.result) { + LogUtils.d( + *rule.matches.toTypedArray(), + NodeInfo.abNodeToNode(nodeVal, target).attr, + actionResult + ) + insertClickLog(rule) + } + } + } + } + + scope.launch(singleThread) { + lastQueryTimeFlow.debounce(debounceTime).collect { + newQueryTask() + } + } onAccessibilityEvent { event -> if (event == null) return@onAccessibilityEvent if (!(event.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED || event.eventType == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED)) return@onAccessibilityEvent if (event.eventType == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) { - if (event.eventTime - appChangeTime > 10_000) { + if (event.eventTime - appChangeTime > 5_000) { if (event.eventTime - lastContentEventTime < 100) { return@onAccessibilityEvent } @@ -133,7 +183,7 @@ class GkdAbService : CompositionAbService({ } if (rightAppId != topActivityFlow.value?.appId) { - // 从 锁屏,下拉通知栏 返回等情况 + // 从 锁屏,下拉通知栏 返回等情况, 应用不会发送事件, 但是系统组件会发送事件 val shizukuTop = getShizukuTopActivity() if (shizukuTop?.appId == rightAppId) { topActivityFlow.value = shizukuTop @@ -146,39 +196,22 @@ class GkdAbService : CompositionAbService({ return@onAccessibilityEvent } - if (evAppId != rightAppId) return@onAccessibilityEvent + if (evAppId != rightAppId) { + return@onAccessibilityEvent + } if (!storeFlow.value.enableService) return@onAccessibilityEvent - if (job?.isActive == true) return@onAccessibilityEvent - - job = scope.launchTry(Dispatchers.Default) { - val activityRule = getCurrentRules() - - for (rule in activityRule.rules) { - if (!isAvailableRule(rule)) continue - val nodeVal = safeActiveWindow ?: continue - val target = rule.query(nodeVal) ?: continue - - if (activityRule !== getCurrentRules()) break - - // 开始 action 延迟 - if (rule.actionDelay > 0 && rule.actionDelayTriggerTime == 0L) { - rule.triggerDelay() - continue - } - - // 如果节点在屏幕外部, click 的结果为 null - val actionResult = rule.performAction(context, target) - if (actionResult.result) { - LogUtils.d( - *rule.matches.toTypedArray(), - NodeInfo.abNodeToNode(nodeVal, target).attr, - actionResult - ) - insertClickLog(rule) - } + val jobVal = job + if (jobVal?.isActive == true) { + if (openAdOptimized == true) { + jobVal.cancel() + } else { + return@onAccessibilityEvent } } + lastQueryTimeFlow.value = event.eventTime + + newQueryTask() } diff --git a/app/src/main/java/li/songe/gkd/util/SubsState.kt b/app/src/main/java/li/songe/gkd/util/SubsState.kt index 4d2089e7c..c2b6ec0f7 100644 --- a/app/src/main/java/li/songe/gkd/util/SubsState.kt +++ b/app/src/main/java/li/songe/gkd/util/SubsState.kt @@ -143,6 +143,10 @@ val appIdToRulesFlow by lazy { } } } + appIdToRules.values.forEach { rules -> + // 让开屏广告类规则全排在最前面 + rules.sortBy { r -> if (r.isOpenAd) 0 else 1 } + } appIdToRules.filter { it.value.isNotEmpty() } }.stateIn>>(appScope, SharingStarted.Eagerly, emptyMap()) }