@@ -16,27 +16,28 @@ data class GkdAction(
1616 val selector : String ,
1717 val fastQuery : Boolean = false ,
1818 val action : String? = null ,
19- val position : RawSubscription .Position ? = null ,
20- )
19+ override val position : RawSubscription .Position ? = null ,
20+ override val swipeArg : RawSubscription .SwipeArg ? = null ,
21+ ) : RawSubscription.LocationProps
2122
2223@Serializable
2324data class ActionResult (
2425 val action : String ,
2526 val result : Boolean ,
26- val shizuku : Boolean = false ,
27+ val shell : Boolean = false ,
2728 val position : Pair <Float , Float >? = null ,
2829)
2930
3031sealed class ActionPerformer (val action : String ) {
3132 abstract fun perform (
3233 node : AccessibilityNodeInfo ,
33- position : RawSubscription .Position ? ,
34+ locationProps : RawSubscription .LocationProps ,
3435 ): ActionResult
3536
3637 data object ClickNode : ActionPerformer (" clickNode" ) {
3738 override fun perform (
3839 node : AccessibilityNodeInfo ,
39- position : RawSubscription .Position ? ,
40+ locationProps : RawSubscription .LocationProps ,
4041 ): ActionResult {
4142 return ActionResult (
4243 action = action,
@@ -48,20 +49,24 @@ sealed class ActionPerformer(val action: String) {
4849 data object ClickCenter : ActionPerformer (" clickCenter" ) {
4950 override fun perform (
5051 node : AccessibilityNodeInfo ,
51- position : RawSubscription .Position ? ,
52+ locationProps : RawSubscription .LocationProps ,
5253 ): ActionResult {
5354 val rect = node.casted.boundsInScreen
54- val p = position?.calc(rect)
55+ val p = locationProps. position?.calc(rect)
5556 val x = p?.first ? : ((rect.right + rect.left) / 2f )
5657 val y = p?.second ? : ((rect.bottom + rect.top) / 2f )
58+ if (! ScreenUtils .inScreen(x, y)) {
59+ return ActionResult (
60+ action = action,
61+ result = false ,
62+ position = x to y,
63+ )
64+ }
5765 return ActionResult (
5866 action = action,
59- result = if (0 <= x && 0 <= y && x <= ScreenUtils .getScreenWidth() && y <= ScreenUtils .getScreenHeight()) {
60- if (shizukuContextFlow.value.tap(x, y)) {
61- return ActionResult (
62- action = action, result = true , shizuku = true , position = x to y
63- )
64- }
67+ result = if (shizukuContextFlow.value.tap(x, y)) {
68+ true
69+ } else {
6570 val gestureDescription = GestureDescription .Builder ()
6671 val path = Path ()
6772 path.moveTo(x, y)
@@ -73,8 +78,6 @@ sealed class ActionPerformer(val action: String) {
7378 A11yService .instance?.dispatchGesture(
7479 gestureDescription.build(), null , null
7580 ) != null
76- } else {
77- false
7881 },
7982 position = x to y
8083 )
@@ -84,65 +87,72 @@ sealed class ActionPerformer(val action: String) {
8487 data object Click : ActionPerformer (" click" ) {
8588 override fun perform (
8689 node : AccessibilityNodeInfo ,
87- position : RawSubscription .Position ? ,
90+ locationProps : RawSubscription .LocationProps ,
8891 ): ActionResult {
8992 if (node.isClickable) {
90- val result = ClickNode .perform(node, position )
93+ val result = ClickNode .perform(node, locationProps )
9194 if (result.result) {
9295 return result
9396 }
9497 }
95- return ClickCenter .perform(node, position )
98+ return ClickCenter .perform(node, locationProps )
9699 }
97100 }
98101
99102 data object LongClickNode : ActionPerformer (" longClickNode" ) {
100103 override fun perform (
101104 node : AccessibilityNodeInfo ,
102- position : RawSubscription .Position ? ,
105+ locationProps : RawSubscription .LocationProps ,
103106 ): ActionResult {
104107 return ActionResult (
105108 action = action,
106- result = node.performAction(AccessibilityNodeInfo .ACTION_LONG_CLICK )
109+ result = node.performAction(AccessibilityNodeInfo .ACTION_LONG_CLICK ).apply {
110+ if (this ) {
111+ Thread .sleep(LongClickCenter .LONG_DURATION )
112+ }
113+ }
107114 )
108115 }
109116 }
110117
111118 data object LongClickCenter : ActionPerformer (" longClickCenter" ) {
119+ const val LONG_DURATION = 500L
112120 override fun perform (
113121 node : AccessibilityNodeInfo ,
114- position : RawSubscription .Position ? ,
122+ locationProps : RawSubscription .LocationProps ,
115123 ): ActionResult {
116124 val rect = node.casted.boundsInScreen
117- val p = position?.calc(rect)
125+ val p = locationProps. position?.calc(rect)
118126 val x = p?.first ? : ((rect.right + rect.left) / 2f )
119127 val y = p?.second ? : ((rect.bottom + rect.top) / 2f )
120128 // 某些系统的 ViewConfiguration.getLongPressTimeout() 返回 300 , 这将导致触发普通的 click 事件
121- val longClickDuration = 500L
129+ if (! ScreenUtils .inScreen(x, y)) {
130+ return ActionResult (
131+ action = action,
132+ result = false ,
133+ position = x to y,
134+ )
135+ }
122136 return ActionResult (
123137 action = action,
124- result = if (0 <= x && 0 <= y && x <= ScreenUtils .getScreenWidth() && y <= ScreenUtils .getScreenHeight()) {
125- if (shizukuContextFlow.value.tap(
126- x, y, longClickDuration
127- )
128- ) {
129- return ActionResult (
130- action = action, result = true , shizuku = true , position = x to y
131- )
132- }
138+ result = if (shizukuContextFlow.value.tap(x, y, LONG_DURATION )) {
139+ true
140+ } else {
133141 val gestureDescription = GestureDescription .Builder ()
134142 val path = Path ()
135143 path.moveTo(x, y)
136144 gestureDescription.addStroke(
137145 GestureDescription .StrokeDescription (
138- path, 0 , longClickDuration
146+ path, 0 , LONG_DURATION
139147 )
140148 )
141- A11yService .instance?.dispatchGesture(
149+ ( A11yService .instance?.dispatchGesture(
142150 gestureDescription.build(), null , null
143- ) != null
144- } else {
145- false
151+ ) != null ).apply {
152+ if (this ) {
153+ Thread .sleep(LONG_DURATION )
154+ }
155+ }
146156 },
147157 position = x to y
148158 )
@@ -152,22 +162,22 @@ sealed class ActionPerformer(val action: String) {
152162 data object LongClick : ActionPerformer (" longClick" ) {
153163 override fun perform (
154164 node : AccessibilityNodeInfo ,
155- position : RawSubscription .Position ? ,
165+ locationProps : RawSubscription .LocationProps ,
156166 ): ActionResult {
157167 if (node.isLongClickable) {
158- val result = LongClickNode .perform(node, position )
168+ val result = LongClickNode .perform(node, locationProps )
159169 if (result.result) {
160170 return result
161171 }
162172 }
163- return LongClickCenter .perform(node, position )
173+ return LongClickCenter .perform(node, locationProps )
164174 }
165175 }
166176
167177 data object Back : ActionPerformer (" back" ) {
168178 override fun perform (
169179 node : AccessibilityNodeInfo ,
170- position : RawSubscription .Position ? ,
180+ locationProps : RawSubscription .LocationProps ,
171181 ): ActionResult {
172182 return ActionResult (
173183 action = action,
@@ -179,18 +189,89 @@ sealed class ActionPerformer(val action: String) {
179189 data object None : ActionPerformer (" none" ) {
180190 override fun perform (
181191 node : AccessibilityNodeInfo ,
182- position : RawSubscription .Position ? ,
192+ locationProps : RawSubscription .LocationProps ,
183193 ): ActionResult {
184194 return ActionResult (
185- action = action, result = true
195+ action = action,
196+ result = true
186197 )
187198 }
188199 }
189200
201+ data object Swipe : ActionPerformer (" swipe" ) {
202+ override fun perform (
203+ node : AccessibilityNodeInfo ,
204+ locationProps : RawSubscription .LocationProps ,
205+ ): ActionResult {
206+ val rect = node.casted.boundsInScreen
207+ val swipeArg = locationProps.swipeArg ? : return None .perform(node, locationProps)
208+ val startP = swipeArg.start.calc(rect)
209+ val endP = swipeArg.end?.calc(rect) ? : startP
210+ if (startP == null || endP == null ) {
211+ return None .perform(node, locationProps)
212+ }
213+ val startX = startP.first
214+ val startY = startP.second
215+ val endX = endP.first
216+ val endY = endP.second
217+ if (! (ScreenUtils .inScreen(startX, startY) && ScreenUtils .inScreen(endX, endY))) {
218+ return ActionResult (
219+ action = action,
220+ result = false ,
221+ position = endX to endY,
222+ )
223+ }
224+ return if (shizukuContextFlow.value.swipe(
225+ startX,
226+ startY,
227+ endX,
228+ endY,
229+ swipeArg.duration
230+ )
231+ ) {
232+ ActionResult (
233+ action = action,
234+ result = true ,
235+ shell = true ,
236+ position = endX to endY,
237+ )
238+ } else {
239+ val gestureDescription = GestureDescription .Builder ()
240+ val path = Path ()
241+ path.moveTo(startX, startY)
242+ path.lineTo(endX, endY)
243+ gestureDescription.addStroke(
244+ GestureDescription .StrokeDescription (
245+ path, 0 , swipeArg.duration
246+ )
247+ )
248+ ActionResult (
249+ action = action,
250+ result = (A11yService .instance?.dispatchGesture(
251+ gestureDescription.build(), null , null
252+ ) != null ).apply {
253+ if (this ) {
254+ Thread .sleep(swipeArg.duration)
255+ }
256+ },
257+ position = endX to endY,
258+ )
259+ }
260+ }
261+ }
262+
190263 companion object {
191264 private val allSubObjects by lazy {
192265 arrayOf(
193- ClickNode , ClickCenter , Click , LongClickNode , LongClickCenter , LongClick , Back , None
266+ ClickNode ,
267+ ClickCenter ,
268+ Click ,
269+ LongClickNode ,
270+ LongClickCenter ,
271+ LongClick ,
272+ Back ,
273+ None ,
274+ Swipe ,
194275 )
195276 }
196277
0 commit comments