修复 选择器有多个条件时无法找到目标的问题
优化 选择器搜索效率
This commit is contained in:
@@ -2,23 +2,7 @@ package com.stardust.automator
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.os.Build
|
||||
|
||||
import com.stardust.automator.filter.BooleanFilter
|
||||
import com.stardust.automator.filter.BoundsFilter
|
||||
import com.stardust.automator.filter.ClassNameFilter
|
||||
import com.stardust.automator.filter.DescFilter
|
||||
import com.stardust.automator.filter.DfsFilter
|
||||
import com.stardust.automator.filter.IdFilter
|
||||
import com.stardust.automator.filter.IntFilter
|
||||
import com.stardust.automator.filter.ListFilter
|
||||
import com.stardust.automator.filter.PackageNameFilter
|
||||
import com.stardust.automator.filter.TextFilter
|
||||
import com.stardust.automator.simple_action.Able
|
||||
import com.stardust.util.Supplier
|
||||
|
||||
import java.util.ArrayList
|
||||
import java.util.LinkedList
|
||||
import java.util.Queue
|
||||
import com.stardust.automator.filter.*
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/8.
|
||||
@@ -26,154 +10,154 @@ import java.util.Queue
|
||||
|
||||
open class UiGlobalSelector {
|
||||
|
||||
private val mFilters = LinkedList<ListFilter>()
|
||||
private val mSelector = Selector()
|
||||
|
||||
//// 第一类筛选条件
|
||||
|
||||
open fun id(id: String): UiGlobalSelector {
|
||||
mFilters.add(IdFilter.equals(id))
|
||||
mSelector.add(IdFilter.equals(id))
|
||||
return this
|
||||
}
|
||||
|
||||
fun idContains(str: String): UiGlobalSelector {
|
||||
mFilters.add(IdFilter.contains(str))
|
||||
mSelector.add(IdFilter.contains(str))
|
||||
return this
|
||||
}
|
||||
|
||||
open fun idStartsWith(prefix: String): UiGlobalSelector {
|
||||
mFilters.add(IdFilter.startsWith(prefix))
|
||||
mSelector.add(IdFilter.startsWith(prefix))
|
||||
return this
|
||||
}
|
||||
|
||||
fun idEndsWith(suffix: String): UiGlobalSelector {
|
||||
mFilters.add(IdFilter.endsWith(suffix))
|
||||
mSelector.add(IdFilter.endsWith(suffix))
|
||||
return this
|
||||
}
|
||||
|
||||
open fun idMatches(regex: String): UiGlobalSelector {
|
||||
mFilters.add(IdFilter.matches(regex))
|
||||
mSelector.add(IdFilter.matches(regex))
|
||||
return this
|
||||
}
|
||||
|
||||
fun text(text: String): UiGlobalSelector {
|
||||
mFilters.add(TextFilter.equals(text))
|
||||
mSelector.add(TextFilters.equals(text))
|
||||
return this
|
||||
}
|
||||
|
||||
fun textContains(str: String): UiGlobalSelector {
|
||||
mFilters.add(TextFilter.contains(str))
|
||||
mSelector.add(TextFilters.contains(str))
|
||||
return this
|
||||
}
|
||||
|
||||
fun textStartsWith(prefix: String): UiGlobalSelector {
|
||||
mFilters.add(TextFilter.startsWith(prefix))
|
||||
mSelector.add(TextFilters.startsWith(prefix))
|
||||
return this
|
||||
}
|
||||
|
||||
fun textEndsWith(suffix: String): UiGlobalSelector {
|
||||
mFilters.add(TextFilter.endsWith(suffix))
|
||||
mSelector.add(TextFilters.endsWith(suffix))
|
||||
return this
|
||||
}
|
||||
|
||||
open fun textMatches(regex: String): UiGlobalSelector {
|
||||
mFilters.add(TextFilter.matches(regex))
|
||||
mSelector.add(TextFilters.matches(regex))
|
||||
return this
|
||||
}
|
||||
|
||||
fun desc(desc: String): UiGlobalSelector {
|
||||
mFilters.add(DescFilter.equals(desc))
|
||||
mSelector.add(DescFilters.equals(desc))
|
||||
return this
|
||||
}
|
||||
|
||||
fun descContains(str: String): UiGlobalSelector {
|
||||
mFilters.add(DescFilter.contains(str))
|
||||
mSelector.add(DescFilters.contains(str))
|
||||
return this
|
||||
}
|
||||
|
||||
fun descStartsWith(prefix: String): UiGlobalSelector {
|
||||
mFilters.add(DescFilter.startsWith(prefix))
|
||||
mSelector.add(DescFilters.startsWith(prefix))
|
||||
return this
|
||||
}
|
||||
|
||||
fun descEndsWith(suffix: String): UiGlobalSelector {
|
||||
mFilters.add(DescFilter.endsWith(suffix))
|
||||
mSelector.add(DescFilters.endsWith(suffix))
|
||||
return this
|
||||
}
|
||||
|
||||
open fun descMatches(regex: String): UiGlobalSelector {
|
||||
mFilters.add(DescFilter.matches(regex))
|
||||
mSelector.add(DescFilters.matches(regex))
|
||||
return this
|
||||
}
|
||||
|
||||
fun className(className: String): UiGlobalSelector {
|
||||
mFilters.add(ClassNameFilter.equals(className))
|
||||
mSelector.add(ClassNameFilters.equals(className))
|
||||
return this
|
||||
}
|
||||
|
||||
fun classNameContains(str: String): UiGlobalSelector {
|
||||
mFilters.add(ClassNameFilter.contains(str))
|
||||
mSelector.add(ClassNameFilters.contains(str))
|
||||
return this
|
||||
}
|
||||
|
||||
fun classNameStartsWith(prefix: String): UiGlobalSelector {
|
||||
mFilters.add(ClassNameFilter.startsWith(prefix))
|
||||
mSelector.add(ClassNameFilters.startsWith(prefix))
|
||||
return this
|
||||
}
|
||||
|
||||
fun classNameEndsWith(suffix: String): UiGlobalSelector {
|
||||
mFilters.add(ClassNameFilter.endsWith(suffix))
|
||||
mSelector.add(ClassNameFilters.endsWith(suffix))
|
||||
return this
|
||||
}
|
||||
|
||||
open fun classNameMatches(regex: String): UiGlobalSelector {
|
||||
mFilters.add(ClassNameFilter.matches(regex))
|
||||
mSelector.add(ClassNameFilters.matches(regex))
|
||||
return this
|
||||
}
|
||||
|
||||
fun packageName(packageName: String): UiGlobalSelector {
|
||||
mFilters.add(PackageNameFilter.equals(packageName))
|
||||
mSelector.add(PackageNameFilter.equals(packageName))
|
||||
return this
|
||||
}
|
||||
|
||||
fun packageNameContains(str: String): UiGlobalSelector {
|
||||
mFilters.add(PackageNameFilter.contains(str))
|
||||
mSelector.add(PackageNameFilter.contains(str))
|
||||
return this
|
||||
}
|
||||
|
||||
fun packageNameStartsWith(prefix: String): UiGlobalSelector {
|
||||
mFilters.add(PackageNameFilter.startsWith(prefix))
|
||||
mSelector.add(PackageNameFilter.startsWith(prefix))
|
||||
return this
|
||||
}
|
||||
|
||||
fun packageNameEndsWith(suffix: String): UiGlobalSelector {
|
||||
mFilters.add(PackageNameFilter.endsWith(suffix))
|
||||
mSelector.add(PackageNameFilter.endsWith(suffix))
|
||||
return this
|
||||
}
|
||||
|
||||
open fun packageNameMatches(regex: String): UiGlobalSelector {
|
||||
mFilters.add(PackageNameFilter.matches(regex))
|
||||
mSelector.add(PackageNameFilter.matches(regex))
|
||||
return this
|
||||
}
|
||||
|
||||
fun bounds(l: Int, t: Int, r: Int, b: Int): UiGlobalSelector {
|
||||
mFilters.add(BoundsFilter(Rect(l, t, r, b), BoundsFilter.TYPE_EQUALS))
|
||||
mSelector.add(BoundsFilter(Rect(l, t, r, b), BoundsFilter.TYPE_EQUALS))
|
||||
return this
|
||||
}
|
||||
|
||||
fun boundsInside(l: Int, t: Int, r: Int, b: Int): UiGlobalSelector {
|
||||
mFilters.add(BoundsFilter(Rect(l, t, r, b), BoundsFilter.TYPE_INSIDE))
|
||||
mSelector.add(BoundsFilter(Rect(l, t, r, b), BoundsFilter.TYPE_INSIDE))
|
||||
return this
|
||||
}
|
||||
|
||||
fun boundsContains(l: Int, t: Int, r: Int, b: Int): UiGlobalSelector {
|
||||
mFilters.add(BoundsFilter(Rect(l, t, r, b), BoundsFilter.TYPE_CONTAINS))
|
||||
mSelector.add(BoundsFilter(Rect(l, t, r, b), BoundsFilter.TYPE_CONTAINS))
|
||||
return this
|
||||
}
|
||||
|
||||
fun drawingOrder(order: Int): UiGlobalSelector {
|
||||
mFilters.add(object : DfsFilter() {
|
||||
override fun isIncluded(nodeInfo: UiObject): Boolean {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && nodeInfo.drawingOrder == order
|
||||
mSelector.add(object : Filter {
|
||||
override fun filter(node: UiObject): Boolean {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && node.drawingOrder == order
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
@@ -186,222 +170,222 @@ open class UiGlobalSelector {
|
||||
//// 第二类筛选条件 -able
|
||||
|
||||
fun checkable(b: Boolean): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.CHECKABLE, b])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.CHECKABLE, b])
|
||||
return this
|
||||
}
|
||||
|
||||
fun checked(b: Boolean): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.CHECKED, b])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.CHECKED, b])
|
||||
return this
|
||||
}
|
||||
|
||||
fun focusable(b: Boolean): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.FOCUSABLE, b])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.FOCUSABLE, b])
|
||||
return this
|
||||
}
|
||||
|
||||
fun focused(b: Boolean): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.FOCUSED, b])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.FOCUSED, b])
|
||||
return this
|
||||
}
|
||||
|
||||
fun visibleToUser(b: Boolean): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.VISIBLE_TO_USER, b])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.VISIBLE_TO_USER, b])
|
||||
return this
|
||||
}
|
||||
|
||||
fun accessibilityFocused(b: Boolean): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.ACCESSIBILITY_FOCUSED, b])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.ACCESSIBILITY_FOCUSED, b])
|
||||
return this
|
||||
}
|
||||
|
||||
fun selected(b: Boolean): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.SELECTED, b])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.SELECTED, b])
|
||||
return this
|
||||
}
|
||||
|
||||
fun clickable(b: Boolean): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.CLICKABLE, b])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.CLICKABLE, b])
|
||||
return this
|
||||
}
|
||||
|
||||
fun longClickable(b: Boolean): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.LONG_CLICKABLE, b])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.LONG_CLICKABLE, b])
|
||||
return this
|
||||
}
|
||||
|
||||
fun enabled(b: Boolean): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.ENABLED, b])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.ENABLED, b])
|
||||
return this
|
||||
}
|
||||
|
||||
fun password(b: Boolean): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.PASSWORD, b])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.PASSWORD, b])
|
||||
return this
|
||||
}
|
||||
|
||||
fun scrollable(b: Boolean): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.SCROLLABLE, b])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.SCROLLABLE, b])
|
||||
return this
|
||||
}
|
||||
|
||||
fun editable(b: Boolean): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.EDITABLE, b])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.EDITABLE, b])
|
||||
return this
|
||||
}
|
||||
|
||||
fun contentInvalid(b: Boolean): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.CONTENT_INVALID, b])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.CONTENT_INVALID, b])
|
||||
return this
|
||||
}
|
||||
|
||||
fun contextClickable(b: Boolean): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.CONTEXT_CLICKABLE, b])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.CONTEXT_CLICKABLE, b])
|
||||
return this
|
||||
}
|
||||
|
||||
fun multiLine(b: Boolean): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.MULTI_LINE, b])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.MULTI_LINE, b])
|
||||
return this
|
||||
}
|
||||
|
||||
fun dismissable(b: Boolean): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.DISMISSABLE, b])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.DISMISSABLE, b])
|
||||
return this
|
||||
}
|
||||
|
||||
fun checkable(): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.CHECKABLE, true])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.CHECKABLE, true])
|
||||
return this
|
||||
}
|
||||
|
||||
fun checked(): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.CHECKED, true])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.CHECKED, true])
|
||||
return this
|
||||
}
|
||||
|
||||
fun focusable(): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.FOCUSABLE, true])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.FOCUSABLE, true])
|
||||
return this
|
||||
}
|
||||
|
||||
fun focused(): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.FOCUSED, true])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.FOCUSED, true])
|
||||
return this
|
||||
}
|
||||
|
||||
fun visibleToUser(): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.VISIBLE_TO_USER, true])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.VISIBLE_TO_USER, true])
|
||||
return this
|
||||
}
|
||||
|
||||
fun accessibilityFocused(): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.ACCESSIBILITY_FOCUSED, true])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.ACCESSIBILITY_FOCUSED, true])
|
||||
return this
|
||||
}
|
||||
|
||||
fun selected(): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.SELECTED, true])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.SELECTED, true])
|
||||
return this
|
||||
}
|
||||
|
||||
fun clickable(): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.CLICKABLE, true])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.CLICKABLE, true])
|
||||
return this
|
||||
}
|
||||
|
||||
fun longClickable(): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.LONG_CLICKABLE, true])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.LONG_CLICKABLE, true])
|
||||
return this
|
||||
}
|
||||
|
||||
fun enabled(): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.ENABLED, true])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.ENABLED, true])
|
||||
return this
|
||||
}
|
||||
|
||||
fun password(): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.PASSWORD, true])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.PASSWORD, true])
|
||||
return this
|
||||
}
|
||||
|
||||
fun scrollable(): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.SCROLLABLE, true])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.SCROLLABLE, true])
|
||||
return this
|
||||
}
|
||||
|
||||
fun editable(): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.EDITABLE, true])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.EDITABLE, true])
|
||||
return this
|
||||
}
|
||||
|
||||
fun contentInvalid(): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.CONTENT_INVALID, true])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.CONTENT_INVALID, true])
|
||||
return this
|
||||
}
|
||||
|
||||
fun contextClickable(): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.CONTEXT_CLICKABLE, true])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.CONTEXT_CLICKABLE, true])
|
||||
return this
|
||||
}
|
||||
|
||||
fun multiLine(): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.MULTI_LINE, true])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.MULTI_LINE, true])
|
||||
return this
|
||||
}
|
||||
|
||||
fun dismissable(): UiGlobalSelector {
|
||||
mFilters.add(BooleanFilter[BooleanFilter.DISMISSABLE, true])
|
||||
mSelector.add(BooleanFilter[BooleanFilter.DISMISSABLE, true])
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
//第三类 int
|
||||
fun depth(d: Int): UiGlobalSelector {
|
||||
mFilters.add(IntFilter(IntFilter.DEPTH, d))
|
||||
mSelector.add(IntFilter(IntFilter.DEPTH, d))
|
||||
return this
|
||||
}
|
||||
|
||||
fun row(d: Int): UiGlobalSelector {
|
||||
mFilters.add(IntFilter(IntFilter.ROW, d))
|
||||
mSelector.add(IntFilter(IntFilter.ROW, d))
|
||||
return this
|
||||
}
|
||||
|
||||
fun rowCount(d: Int): UiGlobalSelector {
|
||||
mFilters.add(IntFilter(IntFilter.ROW_COUNT, d))
|
||||
mSelector.add(IntFilter(IntFilter.ROW_COUNT, d))
|
||||
return this
|
||||
}
|
||||
|
||||
fun rowSpan(d: Int): UiGlobalSelector {
|
||||
mFilters.add(IntFilter(IntFilter.ROW_SPAN, d))
|
||||
mSelector.add(IntFilter(IntFilter.ROW_SPAN, d))
|
||||
return this
|
||||
}
|
||||
|
||||
fun column(d: Int): UiGlobalSelector {
|
||||
mFilters.add(IntFilter(IntFilter.COLUMN, d))
|
||||
mSelector.add(IntFilter(IntFilter.COLUMN, d))
|
||||
return this
|
||||
}
|
||||
|
||||
fun columnCount(d: Int): UiGlobalSelector {
|
||||
mFilters.add(IntFilter(IntFilter.COLUMN_COUNT, d))
|
||||
mSelector.add(IntFilter(IntFilter.COLUMN_COUNT, d))
|
||||
return this
|
||||
}
|
||||
|
||||
fun columnSpan(d: Int): UiGlobalSelector {
|
||||
mFilters.add(IntFilter(IntFilter.COLUMN_SPAN, d))
|
||||
mSelector.add(IntFilter(IntFilter.COLUMN_SPAN, d))
|
||||
return this
|
||||
}
|
||||
|
||||
fun indexInParent(index: Int): UiGlobalSelector {
|
||||
mFilters.add(IntFilter(IntFilter.INDEX_IN_PARENT, index))
|
||||
mSelector.add(IntFilter(IntFilter.INDEX_IN_PARENT, index))
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
fun filter(filter: BooleanFilter.BooleanSupplier): UiGlobalSelector {
|
||||
mFilters.add(object : DfsFilter() {
|
||||
override fun isIncluded(nodeInfo: UiObject): Boolean {
|
||||
return filter[nodeInfo]
|
||||
mSelector.add(object : Filter {
|
||||
override fun filter(node: UiObject): Boolean {
|
||||
return filter[node]
|
||||
}
|
||||
})
|
||||
return this
|
||||
@@ -416,14 +400,7 @@ open class UiGlobalSelector {
|
||||
}
|
||||
|
||||
fun findAndReturnList(node: UiObject, max: Int = Int.MAX_VALUE): List<UiObject> {
|
||||
var list: List<UiObject> = listOf(node)
|
||||
for (filter in mFilters) {
|
||||
val oldMax = filter.maxCount
|
||||
filter.maxCount = max
|
||||
list = filter.filter(list)
|
||||
filter.maxCount = oldMax
|
||||
}
|
||||
return list
|
||||
return DFS(mSelector, max).search(node)
|
||||
}
|
||||
|
||||
fun findOneOf(node: UiObject): UiObject? {
|
||||
@@ -433,19 +410,12 @@ open class UiGlobalSelector {
|
||||
} else collection[0]
|
||||
}
|
||||
|
||||
fun addFilter(filter: ListFilter): UiGlobalSelector {
|
||||
mFilters.add(filter)
|
||||
fun addFilter(filter: Filter): UiGlobalSelector {
|
||||
mSelector.add(filter)
|
||||
return this
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val str = StringBuilder()
|
||||
for (filter in mFilters) {
|
||||
str.append(filter.toString()).append(".")
|
||||
}
|
||||
if (str.isNotEmpty()) {
|
||||
str.deleteCharAt(str.length - 1)
|
||||
}
|
||||
return str.toString()
|
||||
return mSelector.toString()
|
||||
}
|
||||
}
|
||||
|
||||
10
automator/src/main/java/com/stardust/automator/filter/BFS.kt
Normal file
10
automator/src/main/java/com/stardust/automator/filter/BFS.kt
Normal file
@@ -0,0 +1,10 @@
|
||||
package com.stardust.automator.filter
|
||||
|
||||
import com.stardust.automator.UiObject
|
||||
|
||||
class BFS(val filter: Filter, val limit: Int = Int.MAX_VALUE) {
|
||||
|
||||
fun search(node: UiObject) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import java.util.HashMap
|
||||
* Created by Stardust on 2017/3/9.
|
||||
*/
|
||||
|
||||
class BooleanFilter(private val mBooleanSupplier: BooleanSupplier, private val mExceptedValue: Boolean) : DfsFilter() {
|
||||
class BooleanFilter(private val mBooleanSupplier: BooleanSupplier, private val mExceptedValue: Boolean) : Filter {
|
||||
|
||||
interface BooleanSupplier {
|
||||
|
||||
@@ -19,8 +19,8 @@ class BooleanFilter(private val mBooleanSupplier: BooleanSupplier, private val m
|
||||
|
||||
}
|
||||
|
||||
override fun isIncluded(nodeInfo: UiObject): Boolean {
|
||||
return mBooleanSupplier[nodeInfo] == mExceptedValue
|
||||
override fun filter(node: UiObject): Boolean {
|
||||
return mBooleanSupplier[node] == mExceptedValue
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
|
||||
@@ -11,13 +11,13 @@ import java.util.Locale
|
||||
* Created by Stardust on 2017/3/9.
|
||||
*/
|
||||
|
||||
class BoundsFilter(private val mBounds: Rect, private val mType: Int) : DfsFilter() {
|
||||
class BoundsFilter(private val mBounds: Rect, private val mType: Int) : Filter {
|
||||
|
||||
override fun isIncluded(nodeInfo: UiObject): Boolean {
|
||||
override fun filter(node: UiObject): Boolean {
|
||||
if (mType == TYPE_CONTAINS) {
|
||||
return AccessibilityNodeInfoHelper.getBoundsInScreen(nodeInfo).contains(mBounds)
|
||||
return AccessibilityNodeInfoHelper.getBoundsInScreen(node).contains(mBounds)
|
||||
}
|
||||
val boundsInScreen = AccessibilityNodeInfoHelper.getBoundsInScreen(nodeInfo)
|
||||
val boundsInScreen = AccessibilityNodeInfoHelper.getBoundsInScreen(node)
|
||||
return if (mType == TYPE_EQUALS) boundsInScreen == mBounds else mBounds.contains(boundsInScreen)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import com.stardust.automator.UiObject
|
||||
* Created by Stardust on 2017/3/9.
|
||||
*/
|
||||
|
||||
object ClassNameFilter {
|
||||
object ClassNameFilters {
|
||||
|
||||
private val CLASS_NAME_GETTER = object : KeyGetter {
|
||||
override fun getKey(nodeInfo: UiObject): String? {
|
||||
@@ -19,27 +19,27 @@ object ClassNameFilter {
|
||||
}
|
||||
}
|
||||
|
||||
fun equals(text: String): ListFilter {
|
||||
var text = text
|
||||
if (!text.contains(".")) {
|
||||
text = "android.widget.$text"
|
||||
fun equals(text: String): Filter {
|
||||
var className = text
|
||||
if (!className.contains(".")) {
|
||||
className = "android.widget.$className"
|
||||
}
|
||||
return StringEqualsFilter(text, CLASS_NAME_GETTER)
|
||||
return StringEqualsFilter(className, CLASS_NAME_GETTER)
|
||||
}
|
||||
|
||||
fun contains(str: String): ListFilter {
|
||||
fun contains(str: String): Filter {
|
||||
return StringContainsFilter(str, CLASS_NAME_GETTER)
|
||||
}
|
||||
|
||||
fun startsWith(prefix: String): ListFilter {
|
||||
fun startsWith(prefix: String): Filter {
|
||||
return StringStartsWithFilter(prefix, CLASS_NAME_GETTER)
|
||||
}
|
||||
|
||||
fun endsWith(suffix: String): ListFilter {
|
||||
fun endsWith(suffix: String): Filter {
|
||||
return StringEndsWithFilter(suffix, CLASS_NAME_GETTER)
|
||||
}
|
||||
|
||||
fun matches(regex: String): ListFilter {
|
||||
fun matches(regex: String): Filter {
|
||||
return StringMatchesFilter(regex, CLASS_NAME_GETTER)
|
||||
}
|
||||
}
|
||||
42
automator/src/main/java/com/stardust/automator/filter/DFS.kt
Normal file
42
automator/src/main/java/com/stardust/automator/filter/DFS.kt
Normal file
@@ -0,0 +1,42 @@
|
||||
package com.stardust.automator.filter
|
||||
|
||||
import com.stardust.automator.UiObject
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/9.
|
||||
*/
|
||||
|
||||
class DFS(val filter: Filter, val limit: Int = Int.MAX_VALUE) {
|
||||
|
||||
fun search(node: UiObject): List<UiObject> {
|
||||
val list = ArrayList<UiObject>()
|
||||
if (filter.filter(node)) {
|
||||
list.add(node)
|
||||
if (list.size >= limit) {
|
||||
return list
|
||||
}
|
||||
}
|
||||
filterChildren(node, list)
|
||||
return list
|
||||
}
|
||||
|
||||
private fun filterChildren(parent: UiObject, list: MutableList<UiObject>) {
|
||||
for (i in 0 until parent.childCount) {
|
||||
val child = parent.child(i) ?: continue
|
||||
val included = filter.filter(child)
|
||||
if (included) {
|
||||
list.add(child)
|
||||
if (list.size >= limit) {
|
||||
break
|
||||
}
|
||||
}
|
||||
filterChildren(child, list)
|
||||
if (!included) {
|
||||
child.recycle()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import com.stardust.automator.UiObject
|
||||
* Created by Stardust on 2017/3/9.
|
||||
*/
|
||||
|
||||
object DescFilter {
|
||||
object DescFilters {
|
||||
|
||||
private val DESC_GETTER = object : KeyGetter {
|
||||
override fun getKey(nodeInfo: UiObject): String? {
|
||||
@@ -19,23 +19,23 @@ object DescFilter {
|
||||
}
|
||||
}
|
||||
|
||||
fun equals(text: String): ListFilter {
|
||||
fun equals(text: String): Filter {
|
||||
return StringEqualsFilter(text, DESC_GETTER)
|
||||
}
|
||||
|
||||
fun contains(str: String): ListFilter {
|
||||
fun contains(str: String): Filter {
|
||||
return StringContainsFilter(str, DESC_GETTER)
|
||||
}
|
||||
|
||||
fun startsWith(prefix: String): ListFilter {
|
||||
fun startsWith(prefix: String): Filter {
|
||||
return StringStartsWithFilter(prefix, DESC_GETTER)
|
||||
}
|
||||
|
||||
fun endsWith(suffix: String): ListFilter {
|
||||
fun endsWith(suffix: String): Filter {
|
||||
return StringEndsWithFilter(suffix, DESC_GETTER)
|
||||
}
|
||||
|
||||
fun matches(regex: String): ListFilter {
|
||||
fun matches(regex: String): Filter {
|
||||
return StringMatchesFilter(regex, DESC_GETTER)
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package com.stardust.automator.filter
|
||||
|
||||
import com.stardust.automator.UiObject
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/9.
|
||||
*/
|
||||
|
||||
abstract class DfsFilter : ListFilter(), Filter {
|
||||
|
||||
override fun filter(nodes: List<UiObject>): List<UiObject> {
|
||||
val list = ArrayList<UiObject>()
|
||||
for (node in nodes) {
|
||||
if (isIncluded(node)) {
|
||||
list.add(node)
|
||||
}
|
||||
if (list.size >= maxCount) {
|
||||
break
|
||||
}
|
||||
filterChildren(node, list)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
override fun filter(node: UiObject): List<UiObject> {
|
||||
val list = ArrayList<UiObject>()
|
||||
if (isIncluded(node)) {
|
||||
list.add(node)
|
||||
}
|
||||
if (list.size >= maxCount) {
|
||||
return list
|
||||
}
|
||||
filterChildren(node, list)
|
||||
return list
|
||||
}
|
||||
|
||||
private fun filterChildren(parent: UiObject, list: MutableList<UiObject>) {
|
||||
for (i in 0 until parent.childCount) {
|
||||
val child = parent.child(i) ?: continue
|
||||
val included = isIncluded(child)
|
||||
if (included) {
|
||||
list.add(child)
|
||||
}
|
||||
if (list.size >= maxCount) {
|
||||
break
|
||||
}
|
||||
filterChildren(child, list)
|
||||
if (!included) {
|
||||
child.recycle()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun isIncluded(nodeInfo: UiObject): Boolean
|
||||
}
|
||||
@@ -8,6 +8,6 @@ import com.stardust.automator.UiObject
|
||||
|
||||
interface Filter {
|
||||
|
||||
fun filter(node: UiObject): List<UiObject>
|
||||
fun filter(node: UiObject): Boolean
|
||||
|
||||
}
|
||||
|
||||
@@ -19,10 +19,6 @@ object IdFilter {
|
||||
}
|
||||
}
|
||||
|
||||
interface FullIdGetter {
|
||||
fun getFullId(id: String): String
|
||||
}
|
||||
|
||||
fun equals(id: String): StringEqualsFilter {
|
||||
return StringEqualsFilter(id, ID_GETTER)
|
||||
}
|
||||
@@ -31,7 +27,7 @@ object IdFilter {
|
||||
return StringStartsWithFilter(prefix, ID_GETTER)
|
||||
}
|
||||
|
||||
fun endsWith(suffix: String): ListFilter {
|
||||
fun endsWith(suffix: String): StringEndsWithFilter {
|
||||
return StringEndsWithFilter(suffix, ID_GETTER)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,14 +6,14 @@ import com.stardust.automator.UiObject
|
||||
* Created by Stardust on 2017/11/5.
|
||||
*/
|
||||
|
||||
class IntFilter(private val mIntProperty: IntProperty, private val mValue: Int) : DfsFilter() {
|
||||
class IntFilter(private val mIntProperty: IntProperty, private val mValue: Int) : Filter {
|
||||
|
||||
interface IntProperty {
|
||||
operator fun get(`object`: UiObject): Int
|
||||
}
|
||||
|
||||
override fun isIncluded(nodeInfo: UiObject): Boolean {
|
||||
return mIntProperty[nodeInfo] == mValue
|
||||
override fun filter(node: UiObject): Boolean {
|
||||
return mIntProperty[node] == mValue
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.stardust.automator.filter
|
||||
|
||||
import com.stardust.automator.UiObject
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/9.
|
||||
*/
|
||||
|
||||
abstract class ListFilter {
|
||||
|
||||
var maxCount: Int = Integer.MAX_VALUE
|
||||
|
||||
abstract fun filter(nodes: List<UiObject>): List<UiObject>
|
||||
|
||||
abstract class Default : Filter, ListFilter() {
|
||||
|
||||
override fun filter(nodes: List<UiObject>): List<UiObject> {
|
||||
val list = ArrayList<UiObject>()
|
||||
for (node in nodes) {
|
||||
list.addAll(filter(node))
|
||||
if (list.size >= maxCount) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,23 +19,23 @@ object PackageNameFilter {
|
||||
}
|
||||
}
|
||||
|
||||
fun equals(text: String): ListFilter {
|
||||
fun equals(text: String): Filter {
|
||||
return StringEqualsFilter(text, PACKAGE_NAME_GETTER)
|
||||
}
|
||||
|
||||
fun contains(str: String): ListFilter {
|
||||
fun contains(str: String): Filter {
|
||||
return StringContainsFilter(str, PACKAGE_NAME_GETTER)
|
||||
}
|
||||
|
||||
fun startsWith(prefix: String): ListFilter {
|
||||
fun startsWith(prefix: String): Filter {
|
||||
return StringStartsWithFilter(prefix, PACKAGE_NAME_GETTER)
|
||||
}
|
||||
|
||||
fun endsWith(suffix: String): ListFilter {
|
||||
fun endsWith(suffix: String): Filter {
|
||||
return StringEndsWithFilter(suffix, PACKAGE_NAME_GETTER)
|
||||
}
|
||||
|
||||
fun matches(regex: String): ListFilter {
|
||||
fun matches(regex: String): Filter {
|
||||
return StringMatchesFilter(regex, PACKAGE_NAME_GETTER)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.stardust.automator.filter
|
||||
|
||||
import com.stardust.automator.UiObject
|
||||
import java.util.*
|
||||
|
||||
class Selector : Filter {
|
||||
private val mFilters = LinkedList<Filter>()
|
||||
|
||||
override fun filter(node: UiObject): Boolean {
|
||||
for (filter in mFilters) {
|
||||
if (!filter.filter(node)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun add(filter: Filter) {
|
||||
mFilters.add(filter)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val str = StringBuilder()
|
||||
for (filter in mFilters) {
|
||||
str.append(filter.toString()).append(".")
|
||||
}
|
||||
if (str.isNotEmpty()) {
|
||||
str.deleteCharAt(str.length - 1)
|
||||
}
|
||||
return str.toString()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,10 +6,10 @@ import com.stardust.automator.UiObject
|
||||
* Created by Stardust on 2017/3/9.
|
||||
*/
|
||||
|
||||
class StringContainsFilter internal constructor(private val mContains: String, private val mKeyGetter: KeyGetter) : DfsFilter() {
|
||||
class StringContainsFilter internal constructor(private val mContains: String, private val mKeyGetter: KeyGetter) : Filter {
|
||||
|
||||
override fun isIncluded(nodeInfo: UiObject): Boolean {
|
||||
val key = mKeyGetter.getKey(nodeInfo)
|
||||
override fun filter(node: UiObject): Boolean {
|
||||
val key = mKeyGetter.getKey(node)
|
||||
return key != null && key.contains(mContains)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ import com.stardust.automator.UiObject
|
||||
* Created by Stardust on 2017/3/9.
|
||||
*/
|
||||
|
||||
class StringEndsWithFilter(private val mSuffix: String, private val mKeyGetter: KeyGetter) : DfsFilter() {
|
||||
class StringEndsWithFilter(private val mSuffix: String, private val mKeyGetter: KeyGetter) : Filter {
|
||||
|
||||
override fun isIncluded(nodeInfo: UiObject): Boolean {
|
||||
val key = mKeyGetter.getKey(nodeInfo)
|
||||
override fun filter(node: UiObject): Boolean {
|
||||
val key = mKeyGetter.getKey(node)
|
||||
return key != null && key.endsWith(mSuffix)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ import com.stardust.automator.UiObject
|
||||
* Created by Stardust on 2017/3/9.
|
||||
*/
|
||||
|
||||
class StringEqualsFilter(private val mValue: String, private val mKeyGetter: KeyGetter) : DfsFilter() {
|
||||
class StringEqualsFilter(private val mValue: String, private val mKeyGetter: KeyGetter) : Filter {
|
||||
|
||||
override fun isIncluded(nodeInfo: UiObject): Boolean {
|
||||
val key = mKeyGetter.getKey(nodeInfo)
|
||||
override fun filter(node: UiObject): Boolean {
|
||||
val key = mKeyGetter.getKey(node)
|
||||
return if (key != null) {
|
||||
key == mValue
|
||||
} else false
|
||||
|
||||
@@ -6,10 +6,10 @@ import com.stardust.automator.UiObject
|
||||
* Created by Stardust on 2017/3/9.
|
||||
*/
|
||||
|
||||
class StringMatchesFilter internal constructor(private val mRegex: String, private val mKeyGetter: KeyGetter) : DfsFilter() {
|
||||
class StringMatchesFilter internal constructor(private val mRegex: String, private val mKeyGetter: KeyGetter) : Filter {
|
||||
|
||||
override fun isIncluded(nodeInfo: UiObject): Boolean {
|
||||
val key = mKeyGetter.getKey(nodeInfo)
|
||||
override fun filter(node: UiObject): Boolean {
|
||||
val key = mKeyGetter.getKey(node)
|
||||
return key != null && key.matches(mRegex.toRegex())
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ import com.stardust.automator.UiObject
|
||||
* Created by Stardust on 2017/3/9.
|
||||
*/
|
||||
|
||||
class StringStartsWithFilter(private val mPrefix: String, private val mKeyGetter: KeyGetter) : DfsFilter() {
|
||||
class StringStartsWithFilter(private val mPrefix: String, private val mKeyGetter: KeyGetter) : Filter {
|
||||
|
||||
override fun isIncluded(nodeInfo: UiObject): Boolean {
|
||||
val key = mKeyGetter.getKey(nodeInfo)
|
||||
override fun filter(node: UiObject): Boolean {
|
||||
val key = mKeyGetter.getKey(node)
|
||||
return key != null && key.startsWith(mPrefix)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
package com.stardust.automator.filter
|
||||
|
||||
import com.stardust.automator.UiObject
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/9.
|
||||
*/
|
||||
|
||||
class TextFilter private constructor(private val mText: String) : ListFilter.Default() {
|
||||
|
||||
override fun filter(node: UiObject): List<UiObject> {
|
||||
return node.findByText(mText)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private val TEXT_GETTER = object : KeyGetter {
|
||||
override fun getKey(nodeInfo: UiObject): String? {
|
||||
val charSequence = nodeInfo.text
|
||||
return charSequence?.toString()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "text"
|
||||
}
|
||||
}
|
||||
|
||||
fun equals(text: String): ListFilter {
|
||||
return StringEqualsFilter(text, TEXT_GETTER)
|
||||
}
|
||||
|
||||
fun contains(str: String): ListFilter {
|
||||
return StringContainsFilter(str, TEXT_GETTER)
|
||||
}
|
||||
|
||||
fun startsWith(prefix: String): ListFilter {
|
||||
return StringStartsWithFilter(prefix, TEXT_GETTER)
|
||||
}
|
||||
|
||||
fun endsWith(suffix: String): ListFilter {
|
||||
return StringEndsWithFilter(suffix, TEXT_GETTER)
|
||||
}
|
||||
|
||||
fun matches(regex: String): ListFilter {
|
||||
return StringMatchesFilter(regex, TEXT_GETTER)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.stardust.automator.filter
|
||||
|
||||
import com.stardust.automator.UiObject
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/9.
|
||||
*/
|
||||
|
||||
object TextFilters {
|
||||
|
||||
private val TEXT_GETTER = object : KeyGetter {
|
||||
override fun getKey(nodeInfo: UiObject): String? {
|
||||
val charSequence = nodeInfo.text
|
||||
return charSequence?.toString()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "text"
|
||||
}
|
||||
}
|
||||
|
||||
fun equals(text: String): Filter {
|
||||
return StringEqualsFilter(text, TEXT_GETTER)
|
||||
}
|
||||
|
||||
fun contains(str: String): Filter {
|
||||
return StringContainsFilter(str, TEXT_GETTER)
|
||||
}
|
||||
|
||||
fun startsWith(prefix: String): Filter {
|
||||
return StringStartsWithFilter(prefix, TEXT_GETTER)
|
||||
}
|
||||
|
||||
fun endsWith(suffix: String): Filter {
|
||||
return StringEndsWithFilter(suffix, TEXT_GETTER)
|
||||
}
|
||||
|
||||
fun matches(regex: String): Filter {
|
||||
return StringMatchesFilter(regex, TEXT_GETTER)
|
||||
}
|
||||
}
|
||||
@@ -13,11 +13,11 @@ import org.junit.Assert.*
|
||||
*/
|
||||
class DfsFilterTest {
|
||||
|
||||
private class RandomDfsFilter : DfsFilter() {
|
||||
private class RandomFilter : Filter {
|
||||
|
||||
private val mRandom = Random()
|
||||
|
||||
override fun isIncluded(nodeInfo: UiObject): Boolean {
|
||||
override fun filter(node: UiObject): Boolean {
|
||||
return mRandom.nextBoolean()
|
||||
}
|
||||
}
|
||||
@@ -25,9 +25,9 @@ class DfsFilterTest {
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun filter() {
|
||||
val filter = RandomDfsFilter()
|
||||
val filter = RandomFilter()
|
||||
val root = TestUiObject(10)
|
||||
val list = filter.filter(root)
|
||||
val list = DFS(filter).search(root)
|
||||
for (uiObject in list) {
|
||||
if (root !== uiObject)
|
||||
uiObject.recycle()
|
||||
|
||||
Reference in New Issue
Block a user