Skip to content

Commit

Permalink
feat: quickFind+matchLauncher
Browse files Browse the repository at this point in the history
  • Loading branch information
lisonge committed Oct 4, 2023
1 parent eaf2fd6 commit 99ef2b4
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 98 deletions.
31 changes: 22 additions & 9 deletions app/src/main/java/li/songe/gkd/data/Rule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import android.accessibilityservice.AccessibilityService
import android.accessibilityservice.GestureDescription
import android.graphics.Path
import android.graphics.Rect
import android.view.ViewConfiguration
import android.view.accessibility.AccessibilityNodeInfo
import com.blankj.utilcode.util.ScreenUtils
import kotlinx.serialization.Serializable
import li.songe.gkd.service.lastTriggerRuleFlow
import li.songe.gkd.service.launcherActivityIdFlow
import li.songe.gkd.service.querySelector
import li.songe.selector.Selector

Expand All @@ -22,15 +25,17 @@ data class Rule(
val preRules: Set<Rule> = emptySet(),
val cd: Long = defaultMiniCd,
val delay: Long = 0,
val index: Int = 0,
val matchLauncher: Boolean = false,
val quickFind: Boolean = false,

val appId: String = "",
val appId: String,
val activityIds: Set<String> = emptySet(),
val excludeActivityIds: Set<String> = emptySet(),

val key: Int? = null,
val preKeys: Set<Int> = emptySet(),

val index: Int = 0,
val rule: SubscriptionRaw.RuleRaw,
val group: SubscriptionRaw.GroupRaw,
val app: SubscriptionRaw.AppRaw,
Expand All @@ -53,15 +58,14 @@ data class Rule(
val active: Boolean
get() = triggerTime + cd < System.currentTimeMillis()


fun query(nodeInfo: AccessibilityNodeInfo?): AccessibilityNodeInfo? {
if (nodeInfo == null) return null
var target: AccessibilityNodeInfo? = null
for (selector in matches) {
target = nodeInfo.querySelector(selector) ?: return null
target = nodeInfo.querySelector(selector, quickFind) ?: return null
}
for (selector in excludeMatches) {
if (nodeInfo.querySelector(selector) != null) return null
if (nodeInfo.querySelector(selector, quickFind) != null) return null
}
return target
}
Expand All @@ -73,6 +77,9 @@ data class Rule(
if (activityId == null) return false
if (excludeActivityIds.any { activityId.startsWith(it) }) return false
if (activityIds.isEmpty()) return true
if (matchLauncher && launcherActivityIdFlow.value == activityId) {
return true
}
return activityIds.any { activityId.startsWith(it) }
}

Expand All @@ -93,6 +100,7 @@ typealias ActionFc = (context: AccessibilityService, node: AccessibilityNodeInfo
@Serializable
data class ClickAction(
val selector: String,
val quickFind: Boolean = false,
val action: String? = null,
)

Expand All @@ -116,14 +124,19 @@ val clickNode: ActionFc = { _, node ->
val clickCenter: ActionFc = { context, node ->
val react = Rect()
node.getBoundsInScreen(react)
val x = react.left + 50f / 100f * (react.right - react.left)
val y = react.top + 50f / 100f * (react.bottom - react.top)
val x = (react.right + react.left) / 2f
val y = (react.bottom + react.top) / 2f
ActionResult(
action = "clickCenter", result = if (x >= 0 && y >= 0) {
action = "clickCenter",
result = if (0 <= x && 0 <= y && x <= ScreenUtils.getScreenWidth() && y <= ScreenUtils.getScreenHeight()) {
val gestureDescription = GestureDescription.Builder()
val path = Path()
path.moveTo(x, y)
gestureDescription.addStroke(GestureDescription.StrokeDescription(path, 0, 300))
gestureDescription.addStroke(
GestureDescription.StrokeDescription(
path, 0, ViewConfiguration.getTapTimeout().toLong()
)
)
context.dispatchGesture(gestureDescription.build(), null, null)
true
} else {
Expand Down
16 changes: 15 additions & 1 deletion app/src/main/java/li/songe/gkd/data/SubscriptionRaw.kt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ data class SubscriptionRaw(
val excludeActivityIds: List<String>?
val cd: Long?
val delay: Long?
val matchLauncher: Boolean?
val quickFind: Boolean?
val appFilter: AppFilter?
val deviceFilter: DeviceFilter?
}
Expand All @@ -85,6 +87,8 @@ data class SubscriptionRaw(
val name: String? = null,
override val cd: Long? = null,
override val delay: Long? = null,
override val matchLauncher: Boolean?,
override val quickFind: Boolean?,
override val activityIds: List<String>? = null,
override val excludeActivityIds: List<String>? = null,
val groups: List<GroupRaw> = emptyList(),
Expand All @@ -101,6 +105,8 @@ data class SubscriptionRaw(
val key: Int,
override val cd: Long? = null,
override val delay: Long? = null,
override val matchLauncher: Boolean?,
override val quickFind: Boolean?,
override val activityIds: List<String>? = null,
override val excludeActivityIds: List<String>? = null,
val rules: List<RuleRaw> = emptyList(),
Expand Down Expand Up @@ -129,6 +135,8 @@ data class SubscriptionRaw(
val action: String? = null,
override val cd: Long? = null,
override val delay: Long? = null,
override val matchLauncher: Boolean?,
override val quickFind: Boolean?,
override val activityIds: List<String>? = null,
override val excludeActivityIds: List<String>? = null,
val matches: List<String> = emptyList(),
Expand Down Expand Up @@ -242,7 +250,9 @@ data class SubscriptionRaw(
appFilter = rulesJson["appFilter"]?.let {
Singleton.json.decodeFromJsonElement(it)
},
action = getString(rulesJson, "action")
action = getString(rulesJson, "action"),
matchLauncher = getBoolean(rulesJson, "matchLauncher"),
quickFind = getBoolean(rulesJson, "quickFind"),
)
}

Expand Down Expand Up @@ -275,6 +285,8 @@ data class SubscriptionRaw(
appFilter = groupsJson["appFilter"]?.let {
Singleton.json.decodeFromJsonElement(it)
},
matchLauncher = getBoolean(groupsJson, "matchLauncher"),
quickFind = getBoolean(groupsJson, "quickFind"),
)
}

Expand All @@ -299,6 +311,8 @@ data class SubscriptionRaw(
appFilter = appsJson["appFilter"]?.let {
Singleton.json.decodeFromJsonElement(it)
},
matchLauncher = getBoolean(appsJson, "matchLauncher"),
quickFind = getBoolean(appsJson, "quickFind"),
)
}

Expand Down
121 changes: 82 additions & 39 deletions app/src/main/java/li/songe/gkd/service/AbExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package li.songe.gkd.service
import android.accessibilityservice.AccessibilityService
import android.graphics.Rect
import android.view.accessibility.AccessibilityNodeInfo
import com.blankj.utilcode.util.ToastUtils
import li.songe.gkd.util.storeFlow
import li.songe.selector.Selector
import li.songe.selector.Transform

Expand Down Expand Up @@ -56,11 +58,36 @@ fun AccessibilityNodeInfo.getDepth(): Int {
}


fun AccessibilityNodeInfo.querySelector(selector: Selector) =
abTransform.querySelector(this, selector)

//fun AccessibilityNodeInfo.querySelectorAll(selector: Selector) =
// abTransform.querySelectorAll(this, selector)
fun AccessibilityNodeInfo.querySelector(
selector: Selector,
quickFind: Boolean = false,
): AccessibilityNodeInfo? {
if (selector.isMatchRoot) {
if (parent == null) {
val trackNodes = mutableListOf<AccessibilityNodeInfo>()
return selector.match(this, abTransform, trackNodes)
}
return null
}
if (quickFind) {
val canQuickFind = selector.canQuickFind
if (canQuickFind != null) {
// 使用 findAccessibilityNodeInfosByXX 无法查询深层次节点
val trackNodes = mutableListOf<AccessibilityNodeInfo>()
(if (selector.canQuickFind!!.first) {
findAccessibilityNodeInfosByViewId(canQuickFind.second)
} else {
findAccessibilityNodeInfosByText(canQuickFind.second)
}).forEach { childNode ->
val targetNode = selector.match(childNode, abTransform, trackNodes)
if (targetNode != null) return targetNode
}
return null
}
}
// 在一些开屏广告的界面会造成1-2s的阻塞
return abTransform.querySelector(this, selector)
}

// 不可以在 多线程/不同协程作用域 里同时使用
private val tempRect = Rect()
Expand All @@ -69,40 +96,56 @@ private fun AccessibilityNodeInfo.getTempRect(): Rect {
return tempRect
}

val abTransform = Transform<AccessibilityNodeInfo>(getAttr = { node, name ->
when (name) {
"id" -> node.viewIdResourceName
"name" -> node.className
"text" -> node.text
"text.length" -> node.text?.length
"desc" -> node.contentDescription
"desc.length" -> node.contentDescription?.length

"clickable" -> node.isClickable
"checkable" -> node.isCheckable
"checked" -> node.isChecked
"focusable" -> node.isFocusable
"visibleToUser" -> node.isVisibleToUser

"left" -> node.getTempRect().left
"top" -> node.getTempRect().top
"right" -> node.getTempRect().right
"bottom" -> node.getTempRect().bottom

"width" -> node.getTempRect().width()
"height" -> node.getTempRect().height()

"index" -> node.getIndex()
"depth" -> node.getDepth()
"childCount" -> node.childCount
else -> null
}
}, getName = { node -> node.className }, getChildren = { node ->
sequence {
repeat(node.childCount) { i ->
yield(node.getChild(i))
val abTransform = Transform<AccessibilityNodeInfo>(
getAttr = { node, name ->
when (name) {
"id" -> node.viewIdResourceName
"name" -> node.className
"text" -> node.text
"text.length" -> node.text?.length
"desc" -> node.contentDescription
"desc.length" -> node.contentDescription?.length

"clickable" -> node.isClickable
"checkable" -> node.isCheckable
"checked" -> node.isChecked
"focusable" -> node.isFocusable
"visibleToUser" -> node.isVisibleToUser

"left" -> node.getTempRect().left
"top" -> node.getTempRect().top
"right" -> node.getTempRect().right
"bottom" -> node.getTempRect().bottom

"width" -> node.getTempRect().width()
"height" -> node.getTempRect().height()

"index" -> node.getIndex()
"depth" -> node.getDepth()
"childCount" -> node.childCount
else -> null
}
},
getName = { node -> node.className },
getChildren = { node ->
sequence {
repeat(node.childCount) { i ->
yield(node.getChild(i))
}
}
},
getChild = { node, index -> node.getChild(index) },
getParent = { node -> node.parent },
)

private var lastToastTime = -1L
fun toastClickTip() {
if (storeFlow.value.toastWhenClick) {
val t = System.currentTimeMillis()
if (t - lastToastTime > 3000) {
ToastUtils.showShort(storeFlow.value.clickToast)
lastToastTime = t
}
}
}, getChild = { node, index -> node.getChild(index) }, getParent = { node -> node.parent })

}

4 changes: 4 additions & 0 deletions app/src/main/java/li/songe/gkd/service/AbState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import li.songe.gkd.appScope
import li.songe.gkd.data.Rule
import li.songe.gkd.util.appIdToRulesFlow

val launcherActivityIdFlow by lazy {
MutableStateFlow<String?>(null)
}

data class TopActivity(
val appId: String,
val activityId: String? = null,
Expand Down
Loading

0 comments on commit 99ef2b4

Please sign in to comment.