Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] main from gkd-kit:main #12

Merged
merged 9 commits into from
Dec 27, 2023
4 changes: 2 additions & 2 deletions app/src/main/kotlin/li/songe/gkd/data/RawSubscription.kt
Original file line number Diff line number Diff line change
Expand Up @@ -570,11 +570,11 @@ data class RawSubscription(
}
subscription.apps.forEach { a ->
a.groups.findDuplicatedItem { v -> v.key }?.let { v ->
error("duplicated app group: key=${v.key}")
error("duplicated app group: key=${v.key}, appId=${a.id}")
}
a.groups.forEach { g ->
g.rules.findDuplicatedItem { v -> v.key }?.let { v ->
error("duplicated app rule: key=${v.key}, groupKey=${g.key}, appId=${a.id} ")
error("duplicated app rule: key=${v.key}, groupKey=${g.key}, appId=${a.id}")
}
}
}
Expand Down
1 change: 1 addition & 0 deletions app/src/main/kotlin/li/songe/gkd/service/AbExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ val abTransform = Transform(
sequence {
val stack = getChildren(node).toMutableList()
if (stack.isEmpty()) return@sequence
stack.reverse()
val tempNodes = mutableListOf<AccessibilityNodeInfo>()
do {
val top = stack.removeLast()
Expand Down
39 changes: 22 additions & 17 deletions app/src/main/kotlin/li/songe/gkd/service/AbState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package li.songe.gkd.service

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import li.songe.gkd.appScope
import li.songe.gkd.data.AppRule
import li.songe.gkd.data.ClickLog
Expand Down Expand Up @@ -102,25 +104,28 @@ var lastTriggerRule: ResolvedRule? = null
var lastTriggerTime = 0L
var appChangeTime = 0L

val clickLogMutex = Mutex()
fun insertClickLog(rule: ResolvedRule) {
appScope.launchTry(Dispatchers.IO) {
val clickLog = ClickLog(
appId = topActivityFlow.value.appId,
activityId = topActivityFlow.value.activityId,
subsId = rule.subsItem.id,
subsVersion = rule.rawSubs.version,
groupKey = rule.group.key,
groupType = when (rule) {
is AppRule -> SubsConfig.AppGroupType
is GlobalRule -> SubsConfig.GlobalGroupType
},
ruleIndex = rule.index,
ruleKey = rule.key,
)
DbSet.clickLogDao.insert(clickLog)
increaseClickCount()
if (recordStoreFlow.value.clickCount % 100 == 0) {
DbSet.clickLogDao.deleteKeepLatest()
clickLogMutex.withLock {
increaseClickCount()
val clickLog = ClickLog(
appId = topActivityFlow.value.appId,
activityId = topActivityFlow.value.activityId,
subsId = rule.subsItem.id,
subsVersion = rule.rawSubs.version,
groupKey = rule.group.key,
groupType = when (rule) {
is AppRule -> SubsConfig.AppGroupType
is GlobalRule -> SubsConfig.GlobalGroupType
},
ruleIndex = rule.index,
ruleKey = rule.key,
)
DbSet.clickLogDao.insert(clickLog)
if (recordStoreFlow.value.clickCount % 100 == 0) {
DbSet.clickLogDao.deleteKeepLatest()
}
}
}
}
48 changes: 29 additions & 19 deletions app/src/main/kotlin/li/songe/gkd/service/GkdAbService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.PixelFormat
import android.os.Build
import android.util.LruCache
import android.view.Display
import android.view.View
import android.view.WindowManager
Expand Down Expand Up @@ -56,6 +56,7 @@ import li.songe.gkd.util.subsItemsFlow
import li.songe.gkd.util.updateStorage
import li.songe.gkd.util.updateSubscription
import li.songe.selector.Selector
import java.util.concurrent.Executors
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

Expand All @@ -75,7 +76,7 @@ class GkdAbService : CompositionAbService({
val shizukuGrantFlow = MutableStateFlow(false)
var lastCheckShizukuTime = 0L
onAccessibilityEvent { // 借助无障碍轮询校验 shizuku 权限
if (storeFlow.value.enableService && it.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {// 筛选降低判断频率
if (storeFlow.value.enableShizuku && it.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {// 筛选降低判断频率
val t = System.currentTimeMillis()
if (t - lastCheckShizukuTime > 5000L) {
lastCheckShizukuTime = t
Expand All @@ -93,32 +94,37 @@ class GkdAbService : CompositionAbService({

// 当锁屏/上拉通知栏时, safeActiveWindow 没有 activityId, 但是此时 shizuku 获取到是前台 app 的 appId 和 activityId
fun getShizukuTopActivity(): TopActivity? {
if (!storeFlow.value.enableShizuku) return null
// 平均耗时 5 ms
val top = safeGetTasksFc()?.lastOrNull()?.topActivity ?: return null
return TopActivity(appId = top.packageName, activityId = top.className)
}

val activityCache = object : LruCache<Pair<String, String>, Boolean>(128) {
override fun create(key: Pair<String, String>): Boolean {
return kotlin.runCatching {
packageManager.getActivityInfo(
ComponentName(
key.first, key.second
), 0
)
}.getOrNull() != null
}
}

fun isActivity(
appId: String,
activityId: String,
): Boolean {
if (appId == topActivityFlow.value.appId && activityId == topActivityFlow.value.activityId) return true
val r = (try {
packageManager.getActivityInfo(
ComponentName(
appId, activityId
), 0
)
} catch (e: PackageManager.NameNotFoundException) {
null
} != null)
return r
val cacheKey = Pair(appId, activityId)
return activityCache.get(cacheKey)
}

var lastTriggerShizukuTime = 0L
var lastContentEventTime = 0L
val queryThread = Dispatchers.IO.limitedParallelism(1)
val eventThread = Dispatchers.IO.limitedParallelism(1)
val eventExecutor = Executors.newSingleThreadExecutor()
onDestroy {
queryThread.cancel()
}
Expand Down Expand Up @@ -201,8 +207,12 @@ class GkdAbService : CompositionAbService({
val evActivityId = fixedEvent.className


scope.launch(eventThread) {
val eventNode = event.source ?: return@launch
eventExecutor.execute launch@{
val eventNode = if (event.className == null) {
null // https://github.com/gkd-kit/gkd/issues/426 event.clear 已被系统调用
} else {
event.source
}
val oldAppId = topActivityFlow.value.appId
val rightAppId = if (oldAppId == evAppId) {
oldAppId
Expand All @@ -218,7 +228,7 @@ class GkdAbService : CompositionAbService({
)
}
} else {
if (fixedEvent.time - lastTriggerShizukuTime > 300) {
if (storeFlow.value.enableShizuku && fixedEvent.time - lastTriggerShizukuTime > 300) {
val shizukuTop = getShizukuTopActivity()
if (shizukuTop != null && shizukuTop.appId == rightAppId) {
if (shizukuTop.activityId == evActivityId) {
Expand Down Expand Up @@ -297,12 +307,12 @@ class GkdAbService : CompositionAbService({
}

var lastUpdateSubsTime = 0L
onAccessibilityEvent {
onAccessibilityEvent {// 借助 无障碍事件 触发自动检测更新
if (it.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {// 筛选降低判断频率
// 借助 无障碍事件 触发自动检测更新
val i = storeFlow.value.updateSubsInterval
if (i <= 0) return@onAccessibilityEvent
val t = System.currentTimeMillis()
if (i > 0 && t - lastUpdateSubsTime > i.coerceAtLeast(60 * 60_000)) {
if (t - lastUpdateSubsTime > i.coerceAtLeast(60 * 60_000)) {
lastUpdateSubsTime = t
checkSubsUpdate()
}
Expand Down