android-env 1.2.2__py3-none-any.whl → 1.2.3__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.
- android_env/__init__.py +1 -1
- android_env/components/__init__.py +1 -1
- android_env/components/a11y/__init__.py +15 -0
- android_env/components/a11y/a11y_events.py +118 -0
- android_env/components/a11y/a11y_events_test.py +173 -0
- android_env/components/a11y/a11y_forests.py +128 -0
- android_env/components/a11y/a11y_forests_test.py +237 -0
- android_env/components/a11y/a11y_servicer.py +199 -0
- android_env/components/a11y/a11y_servicer_test.py +224 -0
- android_env/components/action_fns.py +132 -0
- android_env/components/action_fns_test.py +227 -0
- android_env/components/action_type.py +26 -3
- android_env/components/adb_call_parser.py +233 -185
- android_env/components/adb_call_parser_test.py +165 -163
- android_env/components/adb_controller.py +19 -28
- android_env/components/adb_controller_test.py +100 -9
- android_env/components/adb_log_stream.py +3 -3
- android_env/components/adb_log_stream_test.py +1 -1
- android_env/components/app_screen_checker.py +15 -13
- android_env/components/app_screen_checker_test.py +1 -1
- android_env/components/config_classes.py +203 -0
- android_env/components/coordinator.py +53 -338
- android_env/components/coordinator_test.py +26 -283
- android_env/components/device_settings.py +174 -0
- android_env/components/device_settings_test.py +228 -0
- android_env/components/dumpsys_thread.py +3 -4
- android_env/components/dumpsys_thread_test.py +1 -1
- android_env/components/errors.py +2 -5
- android_env/components/errors_test.py +1 -1
- android_env/components/log_stream.py +2 -2
- android_env/components/log_stream_test.py +1 -1
- android_env/components/logcat_thread.py +9 -8
- android_env/components/logcat_thread_test.py +2 -3
- android_env/components/{utils.py → pixel_fns.py} +19 -20
- android_env/components/{utils_test.py → pixel_fns_test.py} +20 -15
- android_env/components/setup_step_interpreter.py +45 -37
- android_env/components/setup_step_interpreter_test.py +1 -1
- android_env/components/simulators/__init__.py +1 -1
- android_env/components/simulators/base_simulator.py +79 -23
- android_env/components/simulators/base_simulator_test.py +131 -9
- android_env/components/simulators/emulator/__init__.py +1 -1
- android_env/components/simulators/emulator/emulator_launcher.py +62 -81
- android_env/components/simulators/emulator/emulator_launcher_test.py +120 -43
- android_env/components/simulators/emulator/emulator_simulator.py +111 -98
- android_env/components/simulators/emulator/emulator_simulator_test.py +174 -138
- android_env/components/simulators/fake/__init__.py +1 -1
- android_env/components/simulators/fake/fake_simulator.py +9 -17
- android_env/components/simulators/fake/fake_simulator_test.py +23 -8
- android_env/components/specs.py +1 -1
- android_env/components/specs_test.py +1 -1
- android_env/components/task_manager.py +26 -31
- android_env/components/task_manager_test.py +1 -18
- android_env/env_interface.py +1 -17
- android_env/environment.py +27 -17
- android_env/environment_test.py +51 -25
- android_env/loader.py +57 -43
- android_env/loader_test.py +115 -35
- android_env/proto/__init__.py +1 -1
- android_env/proto/a11y/__init__.py +15 -0
- android_env/proto/a11y/a11y.proto +75 -0
- android_env/proto/a11y/a11y_pb2.py +54 -0
- android_env/proto/a11y/a11y_pb2.pyi +49 -0
- android_env/proto/a11y/a11y_pb2_grpc.py +202 -0
- android_env/proto/a11y/android_accessibility_action.proto +32 -0
- android_env/proto/a11y/android_accessibility_action_pb2.py +37 -0
- android_env/proto/a11y/android_accessibility_action_pb2.pyi +13 -0
- android_env/proto/a11y/android_accessibility_action_pb2_grpc.py +24 -0
- android_env/proto/a11y/android_accessibility_forest.proto +29 -0
- android_env/proto/a11y/android_accessibility_forest_pb2.py +38 -0
- android_env/proto/a11y/android_accessibility_forest_pb2.pyi +13 -0
- android_env/proto/a11y/android_accessibility_forest_pb2_grpc.py +24 -0
- android_env/proto/a11y/android_accessibility_node_info.proto +122 -0
- android_env/proto/a11y/android_accessibility_node_info_clickable_span.proto +49 -0
- android_env/proto/a11y/android_accessibility_node_info_clickable_span_pb2.py +39 -0
- android_env/proto/a11y/android_accessibility_node_info_clickable_span_pb2.pyi +28 -0
- android_env/proto/a11y/android_accessibility_node_info_clickable_span_pb2_grpc.py +24 -0
- android_env/proto/a11y/android_accessibility_node_info_pb2.py +42 -0
- android_env/proto/a11y/android_accessibility_node_info_pb2.pyi +75 -0
- android_env/proto/a11y/android_accessibility_node_info_pb2_grpc.py +24 -0
- android_env/proto/a11y/android_accessibility_tree.proto +29 -0
- android_env/proto/a11y/android_accessibility_tree_pb2.py +38 -0
- android_env/proto/a11y/android_accessibility_tree_pb2.pyi +13 -0
- android_env/proto/a11y/android_accessibility_tree_pb2_grpc.py +24 -0
- android_env/proto/a11y/android_accessibility_window_info.proto +84 -0
- android_env/proto/a11y/android_accessibility_window_info_pb2.py +41 -0
- android_env/proto/a11y/android_accessibility_window_info_pb2.pyi +48 -0
- android_env/proto/a11y/android_accessibility_window_info_pb2_grpc.py +24 -0
- android_env/proto/a11y/rect.proto +30 -0
- android_env/proto/a11y/rect_pb2.py +37 -0
- android_env/proto/a11y/rect_pb2.pyi +17 -0
- android_env/proto/a11y/rect_pb2_grpc.py +24 -0
- android_env/proto/adb.proto +13 -1
- android_env/proto/adb_pb2.py +120 -107
- android_env/proto/adb_pb2.pyi +396 -0
- android_env/proto/adb_pb2_grpc.py +20 -0
- android_env/proto/emulator_controller.proto +1 -1
- android_env/proto/emulator_controller_pb2.py +142 -131
- android_env/proto/emulator_controller_pb2.pyi +672 -0
- android_env/proto/emulator_controller_pb2_grpc.py +497 -136
- android_env/proto/snapshot.proto +1 -1
- android_env/proto/snapshot_pb2.py +30 -19
- android_env/proto/snapshot_pb2.pyi +117 -0
- android_env/proto/snapshot_pb2_grpc.py +20 -0
- android_env/proto/snapshot_service.proto +1 -1
- android_env/proto/snapshot_service_pb2.py +36 -25
- android_env/proto/snapshot_service_pb2.pyi +86 -0
- android_env/proto/snapshot_service_pb2_grpc.py +119 -28
- android_env/proto/state.proto +1 -1
- android_env/proto/state_pb2.py +46 -35
- android_env/proto/state_pb2.pyi +85 -0
- android_env/proto/state_pb2_grpc.py +20 -0
- android_env/proto/task.proto +4 -1
- android_env/proto/task_pb2.py +41 -30
- android_env/proto/task_pb2.pyi +160 -0
- android_env/proto/task_pb2_grpc.py +20 -0
- android_env/wrappers/__init__.py +1 -1
- android_env/wrappers/a11y_grpc_wrapper.py +500 -0
- android_env/wrappers/a11y_grpc_wrapper_test.py +849 -0
- android_env/wrappers/base_wrapper.py +1 -5
- android_env/wrappers/base_wrapper_test.py +1 -7
- android_env/wrappers/discrete_action_wrapper.py +15 -14
- android_env/wrappers/discrete_action_wrapper_test.py +1 -1
- android_env/wrappers/flat_interface_wrapper.py +5 -5
- android_env/wrappers/flat_interface_wrapper_test.py +1 -1
- android_env/wrappers/float_pixels_wrapper.py +5 -4
- android_env/wrappers/float_pixels_wrapper_test.py +1 -1
- android_env/wrappers/gym_wrapper.py +1 -1
- android_env/wrappers/gym_wrapper_test.py +1 -1
- android_env/wrappers/image_rescale_wrapper.py +13 -10
- android_env/wrappers/image_rescale_wrapper_test.py +1 -1
- android_env/wrappers/last_action_wrapper.py +5 -4
- android_env/wrappers/last_action_wrapper_test.py +1 -1
- android_env/wrappers/rate_limit_wrapper.py +1 -1
- android_env/wrappers/rate_limit_wrapper_test.py +1 -1
- android_env/wrappers/tap_action_wrapper.py +12 -12
- android_env/wrappers/tap_action_wrapper_test.py +49 -14
- {android_env-1.2.2.dist-info → android_env-1.2.3.dist-info}/METADATA +14 -16
- android_env-1.2.3.dist-info/RECORD +141 -0
- {android_env-1.2.2.dist-info → android_env-1.2.3.dist-info}/WHEEL +1 -1
- android_env-1.2.2.dist-info/RECORD +0 -88
- {android_env-1.2.2.dist-info → android_env-1.2.3.dist-info/licenses}/LICENSE +0 -0
- {android_env-1.2.2.dist-info → android_env-1.2.3.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,5 @@
|
|
1
1
|
# coding=utf-8
|
2
|
-
# Copyright
|
2
|
+
# Copyright 2024 DeepMind Technologies Limited.
|
3
3
|
#
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
5
|
# you may not use this file except in compliance with the License.
|
@@ -20,7 +20,6 @@ import re
|
|
20
20
|
import subprocess
|
21
21
|
import sys
|
22
22
|
import tempfile
|
23
|
-
from typing import Optional
|
24
23
|
|
25
24
|
from absl import logging
|
26
25
|
from android_env.components import adb_controller as adb_control
|
@@ -41,9 +40,8 @@ _BUTTON_TO_KEYCODE = {
|
|
41
40
|
class AdbCallParser:
|
42
41
|
"""Parses AdbRequest messages and executes corresponding adb commands."""
|
43
42
|
|
44
|
-
def __init__(self, adb_controller: adb_control.AdbController
|
43
|
+
def __init__(self, adb_controller: adb_control.AdbController):
|
45
44
|
self._adb_controller = adb_controller
|
46
|
-
self._tmp_dir = tmp_dir
|
47
45
|
self._handlers = {
|
48
46
|
'install_apk': self._install_apk,
|
49
47
|
'start_activity': self._start_activity,
|
@@ -65,7 +63,7 @@ class AdbCallParser:
|
|
65
63
|
}
|
66
64
|
|
67
65
|
def _execute_command(
|
68
|
-
self, command_args: list[str], timeout:
|
66
|
+
self, command_args: list[str], timeout: float | None
|
69
67
|
) -> tuple[adb_pb2.AdbResponse, bytes]:
|
70
68
|
"""Executes the command, catches errors and populates the response status.
|
71
69
|
|
@@ -109,12 +107,12 @@ class AdbCallParser:
|
|
109
107
|
f'Got: {request.timeout_sec}')
|
110
108
|
return response
|
111
109
|
|
112
|
-
timeout:
|
110
|
+
timeout: float | None = request.timeout_sec or None
|
113
111
|
return self._handlers[command_type](request, timeout)
|
114
112
|
|
115
|
-
def _force_stop(
|
116
|
-
|
117
|
-
|
113
|
+
def _force_stop(
|
114
|
+
self, request: adb_pb2.AdbRequest, timeout: float | None = None
|
115
|
+
) -> adb_pb2.AdbResponse:
|
118
116
|
"""Stops an application.
|
119
117
|
|
120
118
|
Args:
|
@@ -137,9 +135,9 @@ class AdbCallParser:
|
|
137
135
|
|
138
136
|
return response
|
139
137
|
|
140
|
-
def _fetch_current_task_id(
|
141
|
-
|
142
|
-
|
138
|
+
def _fetch_current_task_id(
|
139
|
+
self, full_activity_name: str, timeout: float | None = None
|
140
|
+
) -> int:
|
143
141
|
"""Returns the task ID of the given `full_activity_name`.
|
144
142
|
|
145
143
|
Args:
|
@@ -185,9 +183,8 @@ class AdbCallParser:
|
|
185
183
|
return -1
|
186
184
|
|
187
185
|
def _start_screen_pinning(
|
188
|
-
self,
|
189
|
-
|
190
|
-
timeout: Optional[float] = None) -> adb_pb2.AdbResponse:
|
186
|
+
self, request: adb_pb2.AdbRequest, timeout: float | None = None
|
187
|
+
) -> adb_pb2.AdbResponse:
|
191
188
|
"""Pins an application.
|
192
189
|
|
193
190
|
Args:
|
@@ -219,9 +216,9 @@ class AdbCallParser:
|
|
219
216
|
|
220
217
|
return response
|
221
218
|
|
222
|
-
def _send_broadcast(
|
223
|
-
|
224
|
-
|
219
|
+
def _send_broadcast(
|
220
|
+
self, request: adb_pb2.AdbRequest, timeout: float | None = None
|
221
|
+
) -> adb_pb2.AdbResponse:
|
225
222
|
"""Sends a broadcast.
|
226
223
|
|
227
224
|
Args:
|
@@ -232,21 +229,29 @@ class AdbCallParser:
|
|
232
229
|
An AdbResponse.
|
233
230
|
"""
|
234
231
|
|
235
|
-
|
232
|
+
send_broadcast = request.send_broadcast
|
236
233
|
response = adb_pb2.AdbResponse(status=adb_pb2.AdbResponse.Status.OK)
|
237
|
-
if not
|
234
|
+
if not send_broadcast.action:
|
238
235
|
response.status = adb_pb2.AdbResponse.Status.FAILED_PRECONDITION
|
239
236
|
response.error_message = ('`send_broadcast.{action}` cannot be empty.')
|
240
237
|
return response
|
241
238
|
|
239
|
+
if send_broadcast.component:
|
240
|
+
component_args = ['-n', send_broadcast.component]
|
241
|
+
else:
|
242
|
+
component_args = []
|
243
|
+
|
242
244
|
response, _ = self._execute_command(
|
243
|
-
['shell', 'am', 'broadcast', '-a',
|
244
|
-
|
245
|
+
['shell', 'am', 'broadcast', '-a', send_broadcast.action]
|
246
|
+
+ component_args,
|
247
|
+
timeout=timeout,
|
248
|
+
)
|
249
|
+
|
245
250
|
return response
|
246
251
|
|
247
|
-
def _install_apk(
|
248
|
-
|
249
|
-
|
252
|
+
def _install_apk(
|
253
|
+
self, request: adb_pb2.AdbRequest, timeout: float | None = None
|
254
|
+
) -> adb_pb2.AdbResponse:
|
250
255
|
"""Installs an app given its local path in the filesystem.
|
251
256
|
|
252
257
|
Args:
|
@@ -262,25 +267,46 @@ class AdbCallParser:
|
|
262
267
|
response = adb_pb2.AdbResponse()
|
263
268
|
location_type = install_apk.WhichOneof('location')
|
264
269
|
logging.info('location_type: %s', location_type)
|
265
|
-
if location_type != 'filesystem':
|
266
|
-
response.status = adb_pb2.AdbResponse.Status.FAILED_PRECONDITION
|
267
|
-
response.error_message = (
|
268
|
-
f'Unsupported `install_apk.location` type: {location_type}')
|
269
|
-
return response
|
270
270
|
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
271
|
+
match location_type:
|
272
|
+
case 'filesystem':
|
273
|
+
fpath = install_apk.filesystem.path
|
274
|
+
if not os.path.exists(fpath):
|
275
|
+
response.status = adb_pb2.AdbResponse.Status.INTERNAL_ERROR
|
276
|
+
response.error_message = f'Could not find local_apk_path: {fpath}'
|
277
|
+
return response
|
278
|
+
|
279
|
+
response, _ = self._execute_command(
|
280
|
+
['install', '-r', '-t', '-g', fpath], timeout=timeout
|
281
|
+
)
|
282
|
+
case 'blob':
|
283
|
+
|
284
|
+
# `delete_on_close` was only added in Python 3.12 so we add a switch
|
285
|
+
# here to still support previous Python versions.
|
286
|
+
if sys.version_info >= (3, 12):
|
287
|
+
kwargs = {'suffix': '.apk', 'delete_on_close': False}
|
288
|
+
else:
|
289
|
+
kwargs = {'suffix': '.apk'}
|
290
|
+
|
291
|
+
with tempfile.NamedTemporaryFile(**kwargs) as f:
|
292
|
+
fpath = f.name
|
293
|
+
f.write(install_apk.blob.contents)
|
294
|
+
|
295
|
+
response, _ = self._execute_command(
|
296
|
+
['install', '-r', '-t', '-g', fpath], timeout=timeout
|
297
|
+
)
|
298
|
+
case _:
|
299
|
+
response.status = adb_pb2.AdbResponse.Status.FAILED_PRECONDITION
|
300
|
+
response.error_message = (
|
301
|
+
f'Unsupported `install_apk.location` type: {location_type}'
|
302
|
+
)
|
303
|
+
return response
|
276
304
|
|
277
|
-
response, _ = self._execute_command(['install', '-r', '-t', '-g', fpath],
|
278
|
-
timeout=timeout)
|
279
305
|
return response
|
280
306
|
|
281
|
-
def _start_activity(
|
282
|
-
|
283
|
-
|
307
|
+
def _start_activity(
|
308
|
+
self, request: adb_pb2.AdbRequest, timeout: float | None = None
|
309
|
+
) -> adb_pb2.AdbResponse:
|
284
310
|
"""Starts a given activity.
|
285
311
|
|
286
312
|
Options for `start_activity`:
|
@@ -326,9 +352,9 @@ class AdbCallParser:
|
|
326
352
|
response.start_activity.output = command_output
|
327
353
|
return response
|
328
354
|
|
329
|
-
def _press_button(
|
330
|
-
|
331
|
-
|
355
|
+
def _press_button(
|
356
|
+
self, request: adb_pb2.AdbRequest, timeout: float | None = None
|
357
|
+
) -> adb_pb2.AdbResponse:
|
332
358
|
"""Presses a keyboard key.
|
333
359
|
|
334
360
|
Args:
|
@@ -354,9 +380,8 @@ class AdbCallParser:
|
|
354
380
|
return response
|
355
381
|
|
356
382
|
def _handle_uninstall_package(
|
357
|
-
self,
|
358
|
-
|
359
|
-
timeout: Optional[float] = None) -> adb_pb2.AdbResponse:
|
383
|
+
self, request: adb_pb2.AdbRequest, timeout: float | None = None
|
384
|
+
) -> adb_pb2.AdbResponse:
|
360
385
|
"""Handles UninstallPackage messages.
|
361
386
|
|
362
387
|
Args:
|
@@ -394,9 +419,8 @@ class AdbCallParser:
|
|
394
419
|
return response
|
395
420
|
|
396
421
|
def _get_current_activity(
|
397
|
-
self,
|
398
|
-
|
399
|
-
timeout: Optional[float] = None) -> adb_pb2.AdbResponse:
|
422
|
+
self, request: adb_pb2.AdbRequest, timeout: float | None = None
|
423
|
+
) -> adb_pb2.AdbResponse:
|
400
424
|
"""Fetches current activity.
|
401
425
|
|
402
426
|
Args:
|
@@ -448,9 +472,9 @@ class AdbCallParser:
|
|
448
472
|
response.get_current_activity.full_activity = matches.group(1)
|
449
473
|
return response
|
450
474
|
|
451
|
-
def _get_orientation(
|
452
|
-
|
453
|
-
|
475
|
+
def _get_orientation(
|
476
|
+
self, request: adb_pb2.AdbRequest, timeout: float | None = None
|
477
|
+
) -> adb_pb2.AdbResponse:
|
454
478
|
"""Fetches current device orientation.
|
455
479
|
|
456
480
|
Args:
|
@@ -486,23 +510,30 @@ class AdbCallParser:
|
|
486
510
|
if physical_width:
|
487
511
|
skip_next = int(physical_width.group(1)) < 0
|
488
512
|
|
489
|
-
surface_orientation = re.match(
|
513
|
+
surface_orientation = re.match(
|
514
|
+
r'\s+(SurfaceOrientation|InputDeviceOrientation):\s+(\d)', line
|
515
|
+
)
|
516
|
+
|
490
517
|
if surface_orientation is not None:
|
491
518
|
if skip_next:
|
492
519
|
continue
|
493
|
-
|
520
|
+
if surface_orientation.re.groups < 2:
|
521
|
+
continue
|
522
|
+
orientation = surface_orientation.group(2)
|
494
523
|
logging.info('Done getting orientation: %r', orientation)
|
495
524
|
response.get_orientation.orientation = int(orientation)
|
496
525
|
return response
|
497
526
|
|
498
527
|
response.status = adb_pb2.AdbResponse.Status.INTERNAL_ERROR
|
499
|
-
response.error_message = (
|
500
|
-
|
528
|
+
response.error_message = (
|
529
|
+
'Could not find SurfaceOrientation/InputDeviceOrientation in dumpsys '
|
530
|
+
'output'
|
531
|
+
)
|
501
532
|
return response
|
502
533
|
|
503
|
-
def _push(
|
504
|
-
|
505
|
-
|
534
|
+
def _push(
|
535
|
+
self, request: adb_pb2.AdbRequest, timeout: float | None = None
|
536
|
+
) -> adb_pb2.AdbResponse:
|
506
537
|
"""Uploads contents to the device.
|
507
538
|
|
508
539
|
Args:
|
@@ -520,7 +551,7 @@ class AdbCallParser:
|
|
520
551
|
error_message='Push.path is empty.')
|
521
552
|
|
522
553
|
# Create temporary file with `push` contents.
|
523
|
-
with tempfile.NamedTemporaryFile(
|
554
|
+
with tempfile.NamedTemporaryFile(delete=False) as f:
|
524
555
|
fname = f.name
|
525
556
|
f.write(request.push.content)
|
526
557
|
# Issue `adb push` command to upload file.
|
@@ -531,9 +562,9 @@ class AdbCallParser:
|
|
531
562
|
|
532
563
|
return response
|
533
564
|
|
534
|
-
def _pull(
|
535
|
-
|
536
|
-
|
565
|
+
def _pull(
|
566
|
+
self, request: adb_pb2.AdbRequest, timeout: float | None = None
|
567
|
+
) -> adb_pb2.AdbResponse:
|
537
568
|
"""Downloads file content from the device.
|
538
569
|
|
539
570
|
Args:
|
@@ -551,7 +582,7 @@ class AdbCallParser:
|
|
551
582
|
error_message='Pull.path is empty.')
|
552
583
|
|
553
584
|
# Issue `adb pull` command to copy it to a temporary file.
|
554
|
-
with tempfile.NamedTemporaryFile(
|
585
|
+
with tempfile.NamedTemporaryFile(delete=False) as f:
|
555
586
|
fname = f.name
|
556
587
|
logging.info('Downloading %r to %r.', path, fname)
|
557
588
|
response, _ = self._execute_command(['pull', path, fname],
|
@@ -564,9 +595,9 @@ class AdbCallParser:
|
|
564
595
|
|
565
596
|
return response
|
566
597
|
|
567
|
-
def _input_text(
|
568
|
-
|
569
|
-
|
598
|
+
def _input_text(
|
599
|
+
self, request: adb_pb2.AdbRequest, timeout: float | None = None
|
600
|
+
) -> adb_pb2.AdbResponse:
|
570
601
|
"""Inserts text as keyboard events.
|
571
602
|
|
572
603
|
Args:
|
@@ -587,9 +618,9 @@ class AdbCallParser:
|
|
587
618
|
timeout=timeout)
|
588
619
|
return response
|
589
620
|
|
590
|
-
def _tap(
|
591
|
-
|
592
|
-
|
621
|
+
def _tap(
|
622
|
+
self, request: adb_pb2.AdbRequest, timeout: float | None = None
|
623
|
+
) -> adb_pb2.AdbResponse:
|
593
624
|
"""Taps the device screen.
|
594
625
|
|
595
626
|
Args:
|
@@ -617,9 +648,9 @@ class AdbCallParser:
|
|
617
648
|
|
618
649
|
return response
|
619
650
|
|
620
|
-
def _handle_settings(
|
621
|
-
|
622
|
-
|
651
|
+
def _handle_settings(
|
652
|
+
self, request: adb_pb2.AdbRequest, timeout: float | None = None
|
653
|
+
) -> adb_pb2.AdbResponse:
|
623
654
|
"""Handles SettingsRequest messages.
|
624
655
|
|
625
656
|
Args:
|
@@ -642,70 +673,84 @@ class AdbCallParser:
|
|
642
673
|
namespace = adb_pb2.AdbRequest.SettingsRequest.Namespace.Name(
|
643
674
|
request.name_space).lower()
|
644
675
|
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
676
|
+
match request.WhichOneof('verb'):
|
677
|
+
case 'get':
|
678
|
+
get = request.get
|
679
|
+
if not get.key:
|
680
|
+
response.status = adb_pb2.AdbResponse.Status.FAILED_PRECONDITION
|
681
|
+
response.error_message = (
|
682
|
+
f'Empty SettingsRequest.get.key. Got: {request}.'
|
683
|
+
)
|
684
|
+
return response
|
685
|
+
response, command_output = self._execute_command(
|
686
|
+
['shell', 'settings', 'get', namespace, get.key], timeout=timeout
|
687
|
+
)
|
688
|
+
response.settings.output = command_output
|
689
|
+
case 'put':
|
690
|
+
put = request.put
|
691
|
+
if not put.key or not put.value:
|
692
|
+
response.status = adb_pb2.AdbResponse.Status.FAILED_PRECONDITION
|
693
|
+
response.error_message = (
|
694
|
+
f'Empty SettingsRequest.put key or value. Got: {request}.'
|
695
|
+
)
|
696
|
+
return response
|
697
|
+
response, command_output = self._execute_command(
|
698
|
+
['shell', 'settings', 'put', namespace, put.key, put.value],
|
699
|
+
timeout=timeout,
|
700
|
+
)
|
701
|
+
response.settings.output = command_output
|
702
|
+
case 'delete_key':
|
703
|
+
delete = request.delete_key
|
704
|
+
if not delete.key:
|
705
|
+
response.status = adb_pb2.AdbResponse.Status.FAILED_PRECONDITION
|
706
|
+
response.error_message = (
|
707
|
+
f'Empty SettingsRequest.delete_key.key. Got: {request}.'
|
708
|
+
)
|
709
|
+
return response
|
710
|
+
response, command_output = self._execute_command(
|
711
|
+
['shell', 'settings', 'delete', namespace, delete.key],
|
712
|
+
timeout=timeout,
|
713
|
+
)
|
714
|
+
response.settings.output = command_output
|
715
|
+
case 'reset':
|
716
|
+
reset = request.reset
|
717
|
+
# At least one of `package_name` or `mode` should be given.
|
718
|
+
if (
|
719
|
+
not reset.package_name
|
720
|
+
and reset.mode
|
721
|
+
== adb_pb2.AdbRequest.SettingsRequest.Reset.Mode.UNKNOWN
|
722
|
+
):
|
723
|
+
response.status = adb_pb2.AdbResponse.Status.FAILED_PRECONDITION
|
724
|
+
response.error_message = (
|
725
|
+
'At least one of SettingsRequest.reset package_name or mode'
|
726
|
+
f' should be given. Got: {request}.'
|
727
|
+
)
|
728
|
+
return response
|
729
|
+
|
730
|
+
mode = adb_pb2.AdbRequest.SettingsRequest.Reset.Mode.Name(
|
731
|
+
reset.mode
|
732
|
+
).lower()
|
733
|
+
arg = reset.package_name or mode
|
734
|
+
response, command_output = self._execute_command(
|
735
|
+
['shell', 'settings', 'reset', namespace, arg], timeout=timeout
|
736
|
+
)
|
737
|
+
response.settings.output = command_output
|
738
|
+
case 'list':
|
739
|
+
response, command_output = self._execute_command(
|
740
|
+
['shell', 'settings', 'list', namespace], timeout=timeout
|
741
|
+
)
|
742
|
+
response.settings.output = command_output
|
743
|
+
case _:
|
670
744
|
response.status = adb_pb2.AdbResponse.Status.FAILED_PRECONDITION
|
671
745
|
response.error_message = (
|
672
|
-
f'
|
673
|
-
|
674
|
-
response, command_output = self._execute_command(
|
675
|
-
['shell', 'settings', 'delete', namespace, delete.key],
|
676
|
-
timeout=timeout)
|
677
|
-
response.settings.output = command_output
|
678
|
-
elif verb == 'reset':
|
679
|
-
reset = request.reset
|
680
|
-
# At least one of `package_name` or `mode` should be given.
|
681
|
-
if (not reset.package_name and
|
682
|
-
reset.mode == adb_pb2.AdbRequest.SettingsRequest.Reset.Mode.UNKNOWN):
|
683
|
-
response.status = adb_pb2.AdbResponse.Status.FAILED_PRECONDITION
|
684
|
-
response.error_message = (
|
685
|
-
'At least one of SettingsRequest.reset package_name or mode should '
|
686
|
-
f'be given. Got: {request}.')
|
687
|
-
return response
|
688
|
-
|
689
|
-
mode = adb_pb2.AdbRequest.SettingsRequest.Reset.Mode.Name(
|
690
|
-
reset.mode).lower()
|
691
|
-
arg = reset.package_name or mode
|
692
|
-
response, command_output = self._execute_command(
|
693
|
-
['shell', 'settings', 'reset', namespace, arg], timeout=timeout)
|
694
|
-
response.settings.output = command_output
|
695
|
-
elif verb == 'list':
|
696
|
-
response, command_output = self._execute_command(
|
697
|
-
['shell', 'settings', 'list', namespace], timeout=timeout)
|
698
|
-
response.settings.output = command_output
|
699
|
-
else:
|
700
|
-
response.status = adb_pb2.AdbResponse.Status.FAILED_PRECONDITION
|
701
|
-
response.error_message = (
|
702
|
-
f'Unknown SettingsRequest.verb. Got: {request}.')
|
746
|
+
f'Unknown SettingsRequest.verb. Got: {request}.'
|
747
|
+
)
|
703
748
|
|
704
749
|
return response
|
705
750
|
|
706
|
-
def _handle_generic(
|
707
|
-
|
708
|
-
|
751
|
+
def _handle_generic(
|
752
|
+
self, request: adb_pb2.AdbRequest, timeout: float | None = None
|
753
|
+
) -> adb_pb2.AdbResponse:
|
709
754
|
"""Handles GenericRequest messages.
|
710
755
|
|
711
756
|
Args:
|
@@ -723,9 +768,8 @@ class AdbCallParser:
|
|
723
768
|
return response
|
724
769
|
|
725
770
|
def _handle_package_manager(
|
726
|
-
self,
|
727
|
-
|
728
|
-
timeout: Optional[float] = None) -> adb_pb2.AdbResponse:
|
771
|
+
self, request: adb_pb2.AdbRequest, timeout: float | None = None
|
772
|
+
) -> adb_pb2.AdbResponse:
|
729
773
|
"""Handles PackageManagerRequest messages.
|
730
774
|
|
731
775
|
Args:
|
@@ -740,60 +784,64 @@ class AdbCallParser:
|
|
740
784
|
request = request.package_manager
|
741
785
|
response = adb_pb2.AdbResponse()
|
742
786
|
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
args
|
771
|
-
|
772
|
-
|
773
|
-
args,
|
774
|
-
elif verb == 'grant':
|
775
|
-
grant = request.grant
|
776
|
-
if not grant.package_name:
|
777
|
-
response.status = adb_pb2.AdbResponse.Status.FAILED_PRECONDITION
|
778
|
-
response.error_message = ('`grant.package_name` cannot be empty.')
|
779
|
-
return response
|
780
|
-
|
781
|
-
if not grant.permissions:
|
782
|
-
response.status = adb_pb2.AdbResponse.Status.FAILED_PRECONDITION
|
783
|
-
response.error_message = ('`grant.permissions` cannot be empty.')
|
784
|
-
return response
|
785
|
-
|
786
|
-
for permission in grant.permissions:
|
787
|
-
logging.info('Granting permission: %r', permission)
|
787
|
+
match request.WhichOneof('verb'):
|
788
|
+
case 'list':
|
789
|
+
what = request.list.WhichOneof('what')
|
790
|
+
response, output = self._execute_command(
|
791
|
+
['shell', 'pm', 'list', what], timeout=timeout
|
792
|
+
)
|
793
|
+
|
794
|
+
if output:
|
795
|
+
items = output.decode('utf-8').split()
|
796
|
+
# Remove prefix for each item.
|
797
|
+
prefix = {
|
798
|
+
'features': 'feature:',
|
799
|
+
'libraries': 'library:',
|
800
|
+
'packages': 'package:',
|
801
|
+
}[what]
|
802
|
+
items = [x[len(prefix) :] for x in items if x.startswith(prefix)]
|
803
|
+
response.package_manager.list.items.extend(items)
|
804
|
+
response.package_manager.output = output
|
805
|
+
case 'clear':
|
806
|
+
package_name = request.clear.package_name
|
807
|
+
if not package_name:
|
808
|
+
response.status = adb_pb2.AdbResponse.Status.FAILED_PRECONDITION
|
809
|
+
response.error_message = (
|
810
|
+
f'Empty PackageManagerRequest.clear.package_name. Got: {request}.'
|
811
|
+
)
|
812
|
+
return response
|
813
|
+
|
814
|
+
args = ['shell', 'pm', 'clear', package_name]
|
815
|
+
if request.clear.user_id:
|
816
|
+
args.insert(3, '-f')
|
817
|
+
args.insert(4, request.clear.user_id)
|
788
818
|
response, response.package_manager.output = self._execute_command(
|
789
|
-
|
790
|
-
|
819
|
+
args, timeout=timeout
|
820
|
+
)
|
821
|
+
case 'grant':
|
822
|
+
grant = request.grant
|
823
|
+
if not grant.package_name:
|
824
|
+
response.status = adb_pb2.AdbResponse.Status.FAILED_PRECONDITION
|
825
|
+
response.error_message = '`grant.package_name` cannot be empty.'
|
826
|
+
return response
|
827
|
+
|
828
|
+
if not grant.permissions:
|
829
|
+
response.status = adb_pb2.AdbResponse.Status.FAILED_PRECONDITION
|
830
|
+
response.error_message = '`grant.permissions` cannot be empty.'
|
831
|
+
return response
|
832
|
+
|
833
|
+
for permission in grant.permissions:
|
834
|
+
logging.info('Granting permission: %r', permission)
|
835
|
+
response, response.package_manager.output = self._execute_command(
|
836
|
+
['shell', 'pm', 'grant', grant.package_name, permission],
|
837
|
+
timeout=timeout,
|
838
|
+
)
|
791
839
|
|
792
840
|
return response
|
793
841
|
|
794
|
-
def _handle_dumpsys(
|
795
|
-
|
796
|
-
|
842
|
+
def _handle_dumpsys(
|
843
|
+
self, request: adb_pb2.AdbRequest, timeout: float | None = None
|
844
|
+
) -> adb_pb2.AdbResponse:
|
797
845
|
"""Handles DumpsysRequest messages.
|
798
846
|
|
799
847
|
Args:
|