autoglm-gui 1.4.0__py3-none-any.whl → 1.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. AutoGLM_GUI/__init__.py +11 -0
  2. AutoGLM_GUI/__main__.py +26 -8
  3. AutoGLM_GUI/actions/__init__.py +6 -0
  4. AutoGLM_GUI/actions/handler.py +196 -0
  5. AutoGLM_GUI/actions/types.py +15 -0
  6. AutoGLM_GUI/adb/__init__.py +53 -0
  7. AutoGLM_GUI/adb/apps.py +227 -0
  8. AutoGLM_GUI/adb/connection.py +323 -0
  9. AutoGLM_GUI/adb/device.py +171 -0
  10. AutoGLM_GUI/adb/input.py +67 -0
  11. AutoGLM_GUI/adb/screenshot.py +11 -0
  12. AutoGLM_GUI/adb/timing.py +167 -0
  13. AutoGLM_GUI/adb_plus/keyboard_installer.py +4 -2
  14. AutoGLM_GUI/adb_plus/qr_pair.py +8 -8
  15. AutoGLM_GUI/adb_plus/screenshot.py +22 -1
  16. AutoGLM_GUI/adb_plus/serial.py +38 -20
  17. AutoGLM_GUI/adb_plus/touch.py +4 -9
  18. AutoGLM_GUI/agents/__init__.py +51 -0
  19. AutoGLM_GUI/agents/events.py +19 -0
  20. AutoGLM_GUI/agents/factory.py +153 -0
  21. AutoGLM_GUI/agents/glm/__init__.py +7 -0
  22. AutoGLM_GUI/agents/glm/agent.py +292 -0
  23. AutoGLM_GUI/agents/glm/message_builder.py +81 -0
  24. AutoGLM_GUI/agents/glm/parser.py +110 -0
  25. AutoGLM_GUI/agents/glm/prompts_en.py +77 -0
  26. AutoGLM_GUI/agents/glm/prompts_zh.py +75 -0
  27. AutoGLM_GUI/agents/mai/__init__.py +28 -0
  28. AutoGLM_GUI/agents/mai/agent.py +405 -0
  29. AutoGLM_GUI/agents/mai/parser.py +254 -0
  30. AutoGLM_GUI/agents/mai/prompts.py +103 -0
  31. AutoGLM_GUI/agents/mai/traj_memory.py +91 -0
  32. AutoGLM_GUI/agents/protocols.py +27 -0
  33. AutoGLM_GUI/agents/stream_runner.py +188 -0
  34. AutoGLM_GUI/api/__init__.py +71 -11
  35. AutoGLM_GUI/api/agents.py +190 -229
  36. AutoGLM_GUI/api/control.py +9 -6
  37. AutoGLM_GUI/api/devices.py +112 -28
  38. AutoGLM_GUI/api/health.py +13 -0
  39. AutoGLM_GUI/api/history.py +78 -0
  40. AutoGLM_GUI/api/layered_agent.py +306 -181
  41. AutoGLM_GUI/api/mcp.py +11 -10
  42. AutoGLM_GUI/api/media.py +64 -1
  43. AutoGLM_GUI/api/scheduled_tasks.py +98 -0
  44. AutoGLM_GUI/api/version.py +23 -10
  45. AutoGLM_GUI/api/workflows.py +2 -1
  46. AutoGLM_GUI/config.py +72 -14
  47. AutoGLM_GUI/config_manager.py +98 -27
  48. AutoGLM_GUI/device_adapter.py +263 -0
  49. AutoGLM_GUI/device_manager.py +248 -29
  50. AutoGLM_GUI/device_protocol.py +266 -0
  51. AutoGLM_GUI/devices/__init__.py +49 -0
  52. AutoGLM_GUI/devices/adb_device.py +200 -0
  53. AutoGLM_GUI/devices/mock_device.py +185 -0
  54. AutoGLM_GUI/devices/remote_device.py +177 -0
  55. AutoGLM_GUI/exceptions.py +3 -3
  56. AutoGLM_GUI/history_manager.py +164 -0
  57. AutoGLM_GUI/i18n.py +81 -0
  58. AutoGLM_GUI/metrics.py +13 -20
  59. AutoGLM_GUI/model/__init__.py +5 -0
  60. AutoGLM_GUI/model/message_builder.py +69 -0
  61. AutoGLM_GUI/model/types.py +24 -0
  62. AutoGLM_GUI/models/__init__.py +10 -0
  63. AutoGLM_GUI/models/history.py +96 -0
  64. AutoGLM_GUI/models/scheduled_task.py +71 -0
  65. AutoGLM_GUI/parsers/__init__.py +22 -0
  66. AutoGLM_GUI/parsers/base.py +50 -0
  67. AutoGLM_GUI/parsers/phone_parser.py +58 -0
  68. AutoGLM_GUI/phone_agent_manager.py +118 -367
  69. AutoGLM_GUI/platform_utils.py +31 -2
  70. AutoGLM_GUI/prompt_config.py +15 -0
  71. AutoGLM_GUI/prompts/__init__.py +32 -0
  72. AutoGLM_GUI/scheduler_manager.py +304 -0
  73. AutoGLM_GUI/schemas.py +272 -63
  74. AutoGLM_GUI/scrcpy_stream.py +159 -37
  75. AutoGLM_GUI/server.py +3 -1
  76. AutoGLM_GUI/socketio_server.py +114 -29
  77. AutoGLM_GUI/state.py +10 -30
  78. AutoGLM_GUI/static/assets/{about-DeclntHg.js → about-BQm96DAl.js} +1 -1
  79. AutoGLM_GUI/static/assets/alert-dialog-B42XxGPR.js +1 -0
  80. AutoGLM_GUI/static/assets/chat-C0L2gQYG.js +129 -0
  81. AutoGLM_GUI/static/assets/circle-alert-D4rSJh37.js +1 -0
  82. AutoGLM_GUI/static/assets/dialog-DZ78cEcj.js +45 -0
  83. AutoGLM_GUI/static/assets/history-DFBv7TGc.js +1 -0
  84. AutoGLM_GUI/static/assets/index-Bzyv2yQ2.css +1 -0
  85. AutoGLM_GUI/static/assets/{index-zQ4KKDHt.js → index-CmZSnDqc.js} +1 -1
  86. AutoGLM_GUI/static/assets/index-CssG-3TH.js +11 -0
  87. AutoGLM_GUI/static/assets/label-BCUzE_nm.js +1 -0
  88. AutoGLM_GUI/static/assets/logs-eoFxn5of.js +1 -0
  89. AutoGLM_GUI/static/assets/popover-DLsuV5Sx.js +1 -0
  90. AutoGLM_GUI/static/assets/scheduled-tasks-MyqGJvy_.js +1 -0
  91. AutoGLM_GUI/static/assets/square-pen-zGWYrdfj.js +1 -0
  92. AutoGLM_GUI/static/assets/textarea-BX6y7uM5.js +1 -0
  93. AutoGLM_GUI/static/assets/workflows-CYFs6ssC.js +1 -0
  94. AutoGLM_GUI/static/index.html +2 -2
  95. AutoGLM_GUI/types.py +142 -0
  96. {autoglm_gui-1.4.0.dist-info → autoglm_gui-1.5.0.dist-info}/METADATA +178 -92
  97. autoglm_gui-1.5.0.dist-info/RECORD +157 -0
  98. mai_agent/base.py +137 -0
  99. mai_agent/mai_grounding_agent.py +263 -0
  100. mai_agent/mai_naivigation_agent.py +526 -0
  101. mai_agent/prompt.py +148 -0
  102. mai_agent/unified_memory.py +67 -0
  103. mai_agent/utils.py +73 -0
  104. AutoGLM_GUI/api/dual_model.py +0 -311
  105. AutoGLM_GUI/dual_model/__init__.py +0 -53
  106. AutoGLM_GUI/dual_model/decision_model.py +0 -664
  107. AutoGLM_GUI/dual_model/dual_agent.py +0 -917
  108. AutoGLM_GUI/dual_model/protocols.py +0 -354
  109. AutoGLM_GUI/dual_model/vision_model.py +0 -442
  110. AutoGLM_GUI/mai_ui_adapter/agent_wrapper.py +0 -291
  111. AutoGLM_GUI/phone_agent_patches.py +0 -146
  112. AutoGLM_GUI/static/assets/chat-Iut2yhSw.js +0 -125
  113. AutoGLM_GUI/static/assets/dialog-BfdcBs1x.js +0 -45
  114. AutoGLM_GUI/static/assets/index-5hCCwHA7.css +0 -1
  115. AutoGLM_GUI/static/assets/index-DHF1NZh0.js +0 -12
  116. AutoGLM_GUI/static/assets/workflows-xiplap-r.js +0 -1
  117. autoglm_gui-1.4.0.dist-info/RECORD +0 -100
  118. {autoglm_gui-1.4.0.dist-info → autoglm_gui-1.5.0.dist-info}/WHEEL +0 -0
  119. {autoglm_gui-1.4.0.dist-info → autoglm_gui-1.5.0.dist-info}/entry_points.txt +0 -0
  120. {autoglm_gui-1.4.0.dist-info → autoglm_gui-1.5.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,323 @@
1
+ """ADB connection management for local and remote devices."""
2
+
3
+ import subprocess
4
+ import time
5
+ from dataclasses import dataclass
6
+ from enum import Enum
7
+
8
+ from AutoGLM_GUI.adb.timing import TIMING_CONFIG
9
+ from AutoGLM_GUI.adb_plus.ip import get_wifi_ip
10
+
11
+
12
+ class ConnectionType(Enum):
13
+ """Type of ADB connection."""
14
+
15
+ USB = "usb"
16
+ WIFI = "wifi"
17
+ REMOTE = "remote"
18
+
19
+
20
+ @dataclass
21
+ class DeviceInfo:
22
+ """Information about a connected device."""
23
+
24
+ device_id: str
25
+ status: str
26
+ connection_type: ConnectionType
27
+ model: str | None = None
28
+ android_version: str | None = None
29
+
30
+
31
+ class ADBConnection:
32
+ """
33
+ Manages ADB connections to Android devices.
34
+
35
+ Supports USB, WiFi, and remote TCP/IP connections.
36
+
37
+ Example:
38
+ >>> conn = ADBConnection()
39
+ >>> # Connect to remote device
40
+ >>> conn.connect("192.168.1.100:5555")
41
+ >>> # List devices
42
+ >>> devices = conn.list_devices()
43
+ >>> # Disconnect
44
+ >>> conn.disconnect("192.168.1.100:5555")
45
+ """
46
+
47
+ def __init__(self, adb_path: str = "adb"):
48
+ """
49
+ Initialize ADB connection manager.
50
+
51
+ Args:
52
+ adb_path: Path to ADB executable.
53
+ """
54
+ self.adb_path = adb_path
55
+
56
+ def connect(self, address: str, timeout: int = 10) -> tuple[bool, str]:
57
+ """
58
+ Connect to a remote device via TCP/IP.
59
+
60
+ Args:
61
+ address: Device address in format "host:port" (e.g., "192.168.1.100:5555").
62
+ timeout: Connection timeout in seconds.
63
+
64
+ Returns:
65
+ Tuple of (success, message).
66
+
67
+ Note:
68
+ The remote device must have TCP/IP debugging enabled.
69
+ On the device, run: adb tcpip 5555
70
+ """
71
+ # Validate address format
72
+ if ":" not in address:
73
+ address = f"{address}:5555" # Default ADB port
74
+
75
+ try:
76
+ result = subprocess.run(
77
+ [self.adb_path, "connect", address],
78
+ capture_output=True,
79
+ text=True,
80
+ timeout=timeout,
81
+ )
82
+
83
+ output = result.stdout + result.stderr
84
+
85
+ if "connected" in output.lower():
86
+ return True, f"Connected to {address}"
87
+ elif "already connected" in output.lower():
88
+ return True, f"Already connected to {address}"
89
+ else:
90
+ return False, output.strip()
91
+
92
+ except subprocess.TimeoutExpired:
93
+ return False, f"Connection timeout after {timeout}s"
94
+ except Exception as e:
95
+ return False, f"Connection error: {e}"
96
+
97
+ def disconnect(self, address: str | None = None) -> tuple[bool, str]:
98
+ """
99
+ Disconnect from a remote device.
100
+
101
+ Args:
102
+ address: Device address to disconnect. If None, disconnects all.
103
+
104
+ Returns:
105
+ Tuple of (success, message).
106
+ """
107
+ try:
108
+ cmd = [self.adb_path, "disconnect"]
109
+ if address:
110
+ cmd.append(address)
111
+
112
+ result = subprocess.run(
113
+ cmd, capture_output=True, text=True, encoding="utf-8", timeout=5
114
+ )
115
+
116
+ output = result.stdout + result.stderr
117
+ return True, output.strip() or "Disconnected"
118
+
119
+ except Exception as e:
120
+ return False, f"Disconnect error: {e}"
121
+
122
+ def list_devices(self) -> list[DeviceInfo]:
123
+ """
124
+ List all connected devices.
125
+
126
+ Returns:
127
+ List of DeviceInfo objects.
128
+ """
129
+ try:
130
+ result = subprocess.run(
131
+ [self.adb_path, "devices", "-l"],
132
+ capture_output=True,
133
+ text=True,
134
+ timeout=5,
135
+ )
136
+
137
+ devices = []
138
+ for line in result.stdout.strip().split("\n")[1:]: # Skip header
139
+ if not line.strip():
140
+ continue
141
+
142
+ parts = line.split()
143
+ if len(parts) >= 2:
144
+ device_id = parts[0]
145
+ status = parts[1]
146
+
147
+ # Determine connection type
148
+ if ":" in device_id:
149
+ conn_type = ConnectionType.REMOTE
150
+ elif "emulator" in device_id:
151
+ conn_type = ConnectionType.USB # Emulator via USB
152
+ else:
153
+ conn_type = ConnectionType.USB
154
+
155
+ # Parse additional info
156
+ model = None
157
+ for part in parts[2:]:
158
+ if part.startswith("model:"):
159
+ model = part.split(":", 1)[1]
160
+ break
161
+
162
+ devices.append(
163
+ DeviceInfo(
164
+ device_id=device_id,
165
+ status=status,
166
+ connection_type=conn_type,
167
+ model=model,
168
+ )
169
+ )
170
+
171
+ return devices
172
+
173
+ except Exception as e:
174
+ print(f"Error listing devices: {e}")
175
+ return []
176
+
177
+ def get_device_info(self, device_id: str | None = None) -> DeviceInfo | None:
178
+ """
179
+ Get detailed information about a device.
180
+
181
+ Args:
182
+ device_id: Device ID. If None, uses first available device.
183
+
184
+ Returns:
185
+ DeviceInfo or None if not found.
186
+ """
187
+ devices = self.list_devices()
188
+
189
+ if not devices:
190
+ return None
191
+
192
+ if device_id is None:
193
+ return devices[0]
194
+
195
+ for device in devices:
196
+ if device.device_id == device_id:
197
+ return device
198
+
199
+ return None
200
+
201
+ def is_connected(self, device_id: str | None = None) -> bool:
202
+ """
203
+ Check if a device is connected.
204
+
205
+ Args:
206
+ device_id: Device ID to check. If None, checks if any device is connected.
207
+
208
+ Returns:
209
+ True if connected, False otherwise.
210
+ """
211
+ devices = self.list_devices()
212
+
213
+ if not devices:
214
+ return False
215
+
216
+ if device_id is None:
217
+ return any(d.status == "device" for d in devices)
218
+
219
+ return any(d.device_id == device_id and d.status == "device" for d in devices)
220
+
221
+ def enable_tcpip(
222
+ self, port: int = 5555, device_id: str | None = None
223
+ ) -> tuple[bool, str]:
224
+ """
225
+ Enable TCP/IP debugging on a USB-connected device.
226
+
227
+ This allows subsequent wireless connections to the device.
228
+
229
+ Args:
230
+ port: TCP port for ADB (default: 5555).
231
+ device_id: Device ID. If None, uses first available device.
232
+
233
+ Returns:
234
+ Tuple of (success, message).
235
+
236
+ Note:
237
+ The device must be connected via USB first.
238
+ After this, you can disconnect USB and connect via WiFi.
239
+ """
240
+ try:
241
+ cmd = [self.adb_path]
242
+ if device_id:
243
+ cmd.extend(["-s", device_id])
244
+ cmd.extend(["tcpip", str(port)])
245
+
246
+ result = subprocess.run(
247
+ cmd, capture_output=True, text=True, encoding="utf-8", timeout=10
248
+ )
249
+
250
+ output = result.stdout + result.stderr
251
+
252
+ if "restarting" in output.lower() or result.returncode == 0:
253
+ time.sleep(TIMING_CONFIG.connection.adb_restart_delay)
254
+ return True, f"TCP/IP mode enabled on port {port}"
255
+ else:
256
+ return False, output.strip()
257
+
258
+ except Exception as e:
259
+ return False, f"Error enabling TCP/IP: {e}"
260
+
261
+ def get_device_ip(self, device_id: str | None = None) -> str | None:
262
+ """
263
+ Get the IP address of a connected device.
264
+
265
+ Delegates to adb_plus.ip.get_wifi_ip() for better WiFi interface detection.
266
+
267
+ Args:
268
+ device_id: Device ID. If None, uses first available device.
269
+
270
+ Returns:
271
+ IP address string or None if not found.
272
+ """
273
+ return get_wifi_ip(adb_path=self.adb_path, device_id=device_id)
274
+
275
+ def restart_server(self) -> tuple[bool, str]:
276
+ """
277
+ Restart the ADB server.
278
+
279
+ Returns:
280
+ Tuple of (success, message).
281
+ """
282
+ try:
283
+ # Kill server
284
+ subprocess.run(
285
+ [self.adb_path, "kill-server"], capture_output=True, timeout=5
286
+ )
287
+
288
+ time.sleep(TIMING_CONFIG.connection.server_restart_delay)
289
+
290
+ # Start server
291
+ subprocess.run(
292
+ [self.adb_path, "start-server"], capture_output=True, timeout=5
293
+ )
294
+
295
+ return True, "ADB server restarted"
296
+
297
+ except Exception as e:
298
+ return False, f"Error restarting server: {e}"
299
+
300
+
301
+ def quick_connect(address: str) -> tuple[bool, str]:
302
+ """
303
+ Quick helper to connect to a remote device.
304
+
305
+ Args:
306
+ address: Device address (e.g., "192.168.1.100" or "192.168.1.100:5555").
307
+
308
+ Returns:
309
+ Tuple of (success, message).
310
+ """
311
+ conn = ADBConnection()
312
+ return conn.connect(address)
313
+
314
+
315
+ def list_devices() -> list[DeviceInfo]:
316
+ """
317
+ Quick helper to list connected devices.
318
+
319
+ Returns:
320
+ List of DeviceInfo objects.
321
+ """
322
+ conn = ADBConnection()
323
+ return conn.list_devices()
@@ -0,0 +1,171 @@
1
+ """Device control utilities for Android automation."""
2
+
3
+ import subprocess
4
+ import time
5
+
6
+ from AutoGLM_GUI.adb.apps import APP_PACKAGES
7
+ from AutoGLM_GUI.adb.timing import TIMING_CONFIG
8
+ from AutoGLM_GUI.platform_utils import build_adb_command
9
+
10
+
11
+ def get_current_app(device_id: str | None = None) -> str:
12
+ adb_prefix = build_adb_command(device_id)
13
+
14
+ result = subprocess.run(
15
+ adb_prefix + ["shell", "dumpsys", "window"],
16
+ capture_output=True,
17
+ text=True,
18
+ encoding="utf-8",
19
+ )
20
+ output = result.stdout
21
+ if not output:
22
+ raise ValueError("No output from dumpsys window")
23
+
24
+ for line in output.split("\n"):
25
+ if "mCurrentFocus" in line or "mFocusedApp" in line:
26
+ for app_name, package in APP_PACKAGES.items():
27
+ if package in line:
28
+ return app_name
29
+
30
+ return "System Home"
31
+
32
+
33
+ def tap(
34
+ x: int, y: int, device_id: str | None = None, delay: float | None = None
35
+ ) -> None:
36
+ if delay is None:
37
+ delay = TIMING_CONFIG.device.default_tap_delay
38
+
39
+ adb_prefix = build_adb_command(device_id)
40
+
41
+ subprocess.run(
42
+ adb_prefix + ["shell", "input", "tap", str(x), str(y)], capture_output=True
43
+ )
44
+ time.sleep(delay)
45
+
46
+
47
+ def double_tap(
48
+ x: int, y: int, device_id: str | None = None, delay: float | None = None
49
+ ) -> None:
50
+ if delay is None:
51
+ delay = TIMING_CONFIG.device.default_double_tap_delay
52
+
53
+ adb_prefix = build_adb_command(device_id)
54
+
55
+ subprocess.run(
56
+ adb_prefix + ["shell", "input", "tap", str(x), str(y)], capture_output=True
57
+ )
58
+ time.sleep(TIMING_CONFIG.device.double_tap_interval)
59
+ subprocess.run(
60
+ adb_prefix + ["shell", "input", "tap", str(x), str(y)], capture_output=True
61
+ )
62
+ time.sleep(delay)
63
+
64
+
65
+ def long_press(
66
+ x: int,
67
+ y: int,
68
+ duration_ms: int = 3000,
69
+ device_id: str | None = None,
70
+ delay: float | None = None,
71
+ ) -> None:
72
+ if delay is None:
73
+ delay = TIMING_CONFIG.device.default_long_press_delay
74
+
75
+ adb_prefix = build_adb_command(device_id)
76
+
77
+ subprocess.run(
78
+ adb_prefix
79
+ + ["shell", "input", "swipe", str(x), str(y), str(x), str(y), str(duration_ms)],
80
+ capture_output=True,
81
+ )
82
+ time.sleep(delay)
83
+
84
+
85
+ def swipe(
86
+ start_x: int,
87
+ start_y: int,
88
+ end_x: int,
89
+ end_y: int,
90
+ duration_ms: int | None = None,
91
+ device_id: str | None = None,
92
+ delay: float | None = None,
93
+ ) -> None:
94
+ if delay is None:
95
+ delay = TIMING_CONFIG.device.default_swipe_delay
96
+
97
+ adb_prefix = build_adb_command(device_id)
98
+
99
+ if duration_ms is None:
100
+ dist_sq = (start_x - end_x) ** 2 + (start_y - end_y) ** 2
101
+ duration_ms = int(dist_sq / 1000)
102
+ duration_ms = max(1000, min(duration_ms, 2000))
103
+
104
+ subprocess.run(
105
+ adb_prefix
106
+ + [
107
+ "shell",
108
+ "input",
109
+ "swipe",
110
+ str(start_x),
111
+ str(start_y),
112
+ str(end_x),
113
+ str(end_y),
114
+ str(duration_ms),
115
+ ],
116
+ capture_output=True,
117
+ )
118
+ time.sleep(delay)
119
+
120
+
121
+ def back(device_id: str | None = None, delay: float | None = None) -> None:
122
+ if delay is None:
123
+ delay = TIMING_CONFIG.device.default_back_delay
124
+
125
+ adb_prefix = build_adb_command(device_id)
126
+
127
+ subprocess.run(
128
+ adb_prefix + ["shell", "input", "keyevent", "4"], capture_output=True
129
+ )
130
+ time.sleep(delay)
131
+
132
+
133
+ def home(device_id: str | None = None, delay: float | None = None) -> None:
134
+ if delay is None:
135
+ delay = TIMING_CONFIG.device.default_home_delay
136
+
137
+ adb_prefix = build_adb_command(device_id)
138
+
139
+ subprocess.run(
140
+ adb_prefix + ["shell", "input", "keyevent", "KEYCODE_HOME"], capture_output=True
141
+ )
142
+ time.sleep(delay)
143
+
144
+
145
+ def launch_app(
146
+ app_name: str, device_id: str | None = None, delay: float | None = None
147
+ ) -> bool:
148
+ if delay is None:
149
+ delay = TIMING_CONFIG.device.default_launch_delay
150
+
151
+ if app_name not in APP_PACKAGES:
152
+ return False
153
+
154
+ adb_prefix = build_adb_command(device_id)
155
+ package = APP_PACKAGES[app_name]
156
+
157
+ subprocess.run(
158
+ adb_prefix
159
+ + [
160
+ "shell",
161
+ "monkey",
162
+ "-p",
163
+ package,
164
+ "-c",
165
+ "android.intent.category.LAUNCHER",
166
+ "1",
167
+ ],
168
+ capture_output=True,
169
+ )
170
+ time.sleep(delay)
171
+ return True
@@ -0,0 +1,67 @@
1
+ """Input utilities for Android device text input."""
2
+
3
+ import base64
4
+ import subprocess
5
+
6
+ from AutoGLM_GUI.platform_utils import build_adb_command
7
+
8
+
9
+ def type_text(text: str, device_id: str | None = None) -> None:
10
+ adb_prefix = build_adb_command(device_id)
11
+ encoded_text = base64.b64encode(text.encode("utf-8")).decode("utf-8")
12
+
13
+ subprocess.run(
14
+ adb_prefix
15
+ + [
16
+ "shell",
17
+ "am",
18
+ "broadcast",
19
+ "-a",
20
+ "ADB_INPUT_B64",
21
+ "--es",
22
+ "msg",
23
+ encoded_text,
24
+ ],
25
+ capture_output=True,
26
+ text=True,
27
+ )
28
+
29
+
30
+ def clear_text(device_id: str | None = None) -> None:
31
+ adb_prefix = build_adb_command(device_id)
32
+
33
+ subprocess.run(
34
+ adb_prefix + ["shell", "am", "broadcast", "-a", "ADB_CLEAR_TEXT"],
35
+ capture_output=True,
36
+ text=True,
37
+ )
38
+
39
+
40
+ def detect_and_set_adb_keyboard(device_id: str | None = None) -> str:
41
+ adb_prefix = build_adb_command(device_id)
42
+
43
+ result = subprocess.run(
44
+ adb_prefix + ["shell", "settings", "get", "secure", "default_input_method"],
45
+ capture_output=True,
46
+ text=True,
47
+ )
48
+ current_ime = (result.stdout + result.stderr).strip()
49
+
50
+ if "com.android.adbkeyboard/.AdbIME" not in current_ime:
51
+ subprocess.run(
52
+ adb_prefix + ["shell", "ime", "set", "com.android.adbkeyboard/.AdbIME"],
53
+ capture_output=True,
54
+ text=True,
55
+ )
56
+
57
+ type_text("", device_id)
58
+
59
+ return current_ime
60
+
61
+
62
+ def restore_keyboard(ime: str, device_id: str | None = None) -> None:
63
+ adb_prefix = build_adb_command(device_id)
64
+
65
+ subprocess.run(
66
+ adb_prefix + ["shell", "ime", "set", ime], capture_output=True, text=True
67
+ )
@@ -0,0 +1,11 @@
1
+ """Screenshot utilities for capturing Android device screen.
2
+
3
+ DEPRECATED: This module now delegates to adb_plus.screenshot for the actual implementation.
4
+ Use adb_plus.screenshot directly for new code.
5
+ """
6
+
7
+ from AutoGLM_GUI.adb_plus.screenshot import Screenshot, capture_screenshot
8
+
9
+
10
+ def get_screenshot(device_id: str | None = None, timeout: int = 10) -> Screenshot:
11
+ return capture_screenshot(device_id=device_id, timeout=timeout)