0
# Watchers and Automation
1
2
Automated response system for handling popups, dialogs, and recurring UI events through configurable watchers and monitoring contexts.
3
4
## Capabilities
5
6
### Watcher System
7
8
Monitor UI for specific elements and execute automated responses.
9
10
```python { .api }
11
class Device:
12
@cached_property
13
def watcher(self) -> Watcher:
14
"""Access device watcher for automated UI responses"""
15
16
class Watcher:
17
def when(self, selector: Dict[str, Any]) -> WatcherItem:
18
"""
19
Create watcher for UI element.
20
21
Parameters:
22
- selector: UI element selector criteria
23
24
Returns:
25
WatcherItem for configuring response
26
"""
27
28
def remove(self, name: str = None):
29
"""
30
Remove watcher by name.
31
32
Parameters:
33
- name: Watcher name to remove, None removes all
34
"""
35
36
def list(self) -> List[str]:
37
"""List all active watcher names"""
38
39
def run(self):
40
"""Run watchers once to check for triggers"""
41
42
def start(self, interval: float = 2.0):
43
"""
44
Start background watcher monitoring.
45
46
Parameters:
47
- interval: Check interval in seconds
48
"""
49
50
def stop(self):
51
"""Stop background watcher monitoring"""
52
```
53
54
Usage examples:
55
56
```python
57
d = u2.connect()
58
59
# Create watchers for common dialogs
60
d.watcher.when(text="OK").click()
61
d.watcher.when(text="Allow").click()
62
d.watcher.when(text="Cancel").click()
63
64
# Handle permission dialogs
65
d.watcher.when(textContains="permission").click(text="Allow")
66
d.watcher.when(textContains="Location").click(text="Grant")
67
68
# Start background monitoring
69
d.watcher.start(interval=1.0) # Check every second
70
71
# Your automation code here
72
d.app_start("com.example.app")
73
# Watchers automatically handle popups
74
75
# Stop monitoring when done
76
d.watcher.stop()
77
78
# Remove specific watchers
79
d.watcher.remove("OK_watcher")
80
d.watcher.remove() # Remove all
81
```
82
83
### Watch Context
84
85
Advanced watching system with XPath support and context management.
86
87
```python { .api }
88
class Device:
89
def watch_context(self, autostart: bool = True, builtin: bool = False) -> WatchContext:
90
"""
91
Create watch context for advanced automation.
92
93
Parameters:
94
- autostart: Start monitoring automatically
95
- builtin: Use built-in system watchers
96
97
Returns:
98
WatchContext for configuring watchers
99
"""
100
101
class WatchContext:
102
def __init__(self, d: Device, builtin: bool = False):
103
"""Initialize watch context"""
104
105
def when(self, xpath: str) -> WatchContextItem:
106
"""
107
Create XPath-based watcher.
108
109
Parameters:
110
- xpath: XPath expression to watch for
111
112
Returns:
113
WatchContextItem for configuring response
114
"""
115
116
def start(self):
117
"""Start watch context monitoring"""
118
119
def stop(self):
120
"""Stop watch context monitoring"""
121
122
def wait_stable(self, timeout: float = 10.0) -> bool:
123
"""
124
Wait for UI to become stable (no watcher triggers).
125
126
Parameters:
127
- timeout: Maximum wait time
128
129
Returns:
130
bool: True if UI became stable
131
"""
132
```
133
134
Usage examples:
135
136
```python
137
d = u2.connect()
138
139
# Create watch context
140
with d.watch_context() as ctx:
141
# XPath-based watchers
142
ctx.when('//*[@text="OK"]').click()
143
ctx.when('//*[@text="Skip"]').click()
144
ctx.when('//android.widget.Button[contains(@text, "Allow")]').click()
145
146
# Handle ads and interruptions
147
ctx.when('//*[@resource-id="close_ad"]').click()
148
ctx.when('//*[contains(@text, "Ad")]/..//*[@text="✕"]').click()
149
150
# Run automation
151
d.app_start("com.example.app")
152
153
# Wait for UI to stabilize
154
ctx.wait_stable(timeout=30)
155
156
# Continue with automation
157
d.click(100, 200)
158
159
# Context automatically stops when exiting
160
```
161
162
### Advanced Watcher Configuration
163
164
Configure complex watcher behaviors and responses.
165
166
```python { .api }
167
class WatcherItem:
168
def click(self, **kwargs) -> WatcherItem:
169
"""Click matching element with optional selector refinement"""
170
171
def press(self, key: str) -> WatcherItem:
172
"""Press hardware key when element appears"""
173
174
def call(self, func) -> WatcherItem:
175
"""Call custom function when element appears"""
176
177
class WatchContextItem:
178
def click(self) -> WatchContextItem:
179
"""Click the matched XPath element"""
180
181
def press(self, key: str) -> WatchContextItem:
182
"""Press hardware key when XPath matches"""
183
184
def call(self, func) -> WatchContextItem:
185
"""Call custom function when XPath matches"""
186
```
187
188
Usage examples:
189
190
```python
191
d = u2.connect()
192
193
# Custom watcher functions
194
def handle_popup():
195
print("Popup appeared, handling...")
196
d.press("back")
197
d.press("back")
198
199
def skip_ad():
200
print("Ad detected, skipping...")
201
d.click(0.9, 0.1) # Top-right corner
202
203
# Configure watcher responses
204
d.watcher.when(text="Update").press("back")
205
d.watcher.when(textContains="popup").call(handle_popup)
206
d.watcher.when(resourceId="ad_container").call(skip_ad)
207
208
# XPath watcher with custom function
209
with d.watch_context() as ctx:
210
ctx.when('//*[@text="Rate App"]').call(lambda: d.press("back"))
211
ctx.when('//android.widget.VideoView').call(skip_ad)
212
213
# Run automation with watchers active
214
d.app_start("com.social.app")
215
ctx.wait_stable()
216
```
217
218
### Built-in System Watchers
219
220
Use pre-configured watchers for common system dialogs.
221
222
```python
223
d = u2.connect()
224
225
# Enable built-in system watchers
226
with d.watch_context(builtin=True) as ctx:
227
# Built-in watchers handle:
228
# - ANR (Application Not Responding) dialogs
229
# - Permission dialogs
230
# - System update notifications
231
# - Crash dialogs
232
233
# Your automation code
234
d.app_start("com.potentially.unstable.app")
235
236
# Built-in watchers automatically handle system interruptions
237
ctx.wait_stable(timeout=60)
238
```
239
240
### Watcher Monitoring and Debugging
241
242
Monitor watcher activity and debug watcher configurations.
243
244
```python
245
d = u2.connect()
246
247
# List active watchers
248
watchers = d.watcher.list()
249
print(f"Active watchers: {watchers}")
250
251
# Manual watcher execution
252
d.watcher.run() # Check all watchers once
253
254
# Monitor watcher triggers
255
import logging
256
u2.enable_pretty_logging(logging.DEBUG)
257
258
# Create watchers with names for tracking
259
d.watcher.when(text="OK").click().name("ok_handler")
260
d.watcher.when(text="Cancel").press("back").name("cancel_handler")
261
262
# Start monitoring with logging
263
d.watcher.start(interval=0.5)
264
265
# Run automation - watcher activity will be logged
266
d.app_start("com.example.app")
267
time.sleep(10)
268
269
d.watcher.stop()
270
```
271
272
### Complex Automation Patterns
273
274
Combine watchers with application lifecycle for robust automation.
275
276
```python
277
d = u2.connect()
278
279
def robust_app_automation(package_name):
280
"""Robust app automation with comprehensive error handling"""
281
282
with d.watch_context(builtin=True) as ctx:
283
# Handle common interruptions
284
ctx.when('//*[@text="OK"]').click()
285
ctx.when('//*[@text="Allow"]').click()
286
ctx.when('//*[@text="Skip"]').click()
287
ctx.when('//*[@text="Not now"]').click()
288
ctx.when('//*[contains(@text, "Update")]').click(text="Later")
289
290
# Handle ads
291
ctx.when('//*[@resource-id="close_button"]').click()
292
ctx.when('//*[@text="✕"]').click()
293
294
# Launch app with session monitoring
295
with d.session(package_name) as session:
296
ctx.wait_stable(timeout=30)
297
298
# App-specific automation
299
yield session # Allow caller to perform actions
300
301
# Verify app is still running
302
if not session.running():
303
print("App crashed, restarting...")
304
session.restart()
305
ctx.wait_stable(timeout=15)
306
307
# Usage
308
for session in robust_app_automation("com.example.app"):
309
# Perform automation with robust error handling
310
session.click(100, 200)
311
session.send_keys("test input")
312
313
# UI interactions protected by watchers
314
session(text="Submit").click()
315
316
# Wait and continue
317
time.sleep(5)
318
```
319
320
### Toast Monitoring Integration
321
322
Combine watchers with toast message monitoring for comprehensive UI monitoring.
323
324
```python
325
d = u2.connect()
326
327
# Monitor toasts alongside watchers
328
with d.watch_context() as ctx:
329
# Handle error dialogs
330
ctx.when('//*[@text="Error"]').click(text="OK")
331
ctx.when('//*[@text="Failed"]').press("back")
332
333
# Start app
334
d.app_start("com.example.app")
335
336
# Monitor for success/error messages
337
ctx.wait_stable()
338
339
# Check toast messages
340
toast = d.last_toast
341
if toast and "error" in toast.lower():
342
print(f"Error toast detected: {toast}")
343
d.press("back")
344
elif toast and "success" in toast.lower():
345
print(f"Success toast: {toast}")
346
347
d.clear_toast()
348
```