android-env 1.2.1__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 +239 -196
- android_env/components/adb_call_parser_test.py +179 -209
- android_env/components/adb_controller.py +90 -52
- android_env/components/adb_controller_test.py +187 -16
- android_env/components/adb_log_stream.py +17 -5
- android_env/components/adb_log_stream_test.py +17 -3
- android_env/components/app_screen_checker.py +17 -15
- android_env/components/app_screen_checker_test.py +7 -8
- android_env/components/config_classes.py +203 -0
- android_env/components/coordinator.py +102 -338
- android_env/components/coordinator_test.py +59 -199
- 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 +52 -10
- android_env/components/errors_test.py +110 -0
- android_env/components/log_stream.py +7 -5
- android_env/components/log_stream_test.py +1 -1
- android_env/components/logcat_thread.py +9 -8
- android_env/components/logcat_thread_test.py +3 -4
- android_env/components/{utils.py → pixel_fns.py} +20 -20
- android_env/components/{utils_test.py → pixel_fns_test.py} +20 -15
- android_env/components/setup_step_interpreter.py +47 -39
- android_env/components/setup_step_interpreter_test.py +4 -4
- android_env/components/simulators/__init__.py +1 -1
- android_env/components/simulators/base_simulator.py +116 -44
- 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 +67 -77
- android_env/components/simulators/emulator/emulator_launcher_test.py +153 -49
- android_env/components/simulators/emulator/emulator_simulator.py +276 -95
- android_env/components/simulators/emulator/emulator_simulator_test.py +314 -89
- android_env/components/simulators/fake/__init__.py +1 -1
- android_env/components/simulators/fake/fake_simulator.py +17 -25
- android_env/components/simulators/fake/fake_simulator_test.py +29 -12
- android_env/components/specs.py +18 -28
- android_env/components/specs_test.py +1 -44
- android_env/components/task_manager.py +48 -48
- android_env/components/task_manager_test.py +71 -60
- android_env/env_interface.py +37 -23
- android_env/environment.py +83 -51
- android_env/environment_test.py +68 -29
- 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 +17 -6
- 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 +68 -63
- 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 +505 -142
- android_env/proto/snapshot.proto +169 -0
- android_env/proto/snapshot_pb2.py +47 -0
- android_env/proto/snapshot_pb2.pyi +117 -0
- android_env/proto/snapshot_pb2_grpc.py +24 -0
- android_env/proto/snapshot_service.proto +289 -0
- android_env/proto/snapshot_service_pb2.py +54 -0
- android_env/proto/snapshot_service_pb2.pyi +86 -0
- android_env/proto/snapshot_service_pb2_grpc.py +487 -0
- android_env/proto/state.proto +63 -0
- android_env/proto/state_pb2.py +63 -0
- android_env/proto/state_pb2.pyi +85 -0
- android_env/proto/state_pb2_grpc.py +24 -0
- android_env/proto/task.proto +5 -1
- android_env/proto/task_pb2.py +42 -31
- 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 +34 -13
- android_env/wrappers/base_wrapper_test.py +22 -16
- android_env/wrappers/discrete_action_wrapper.py +18 -17
- android_env/wrappers/discrete_action_wrapper_test.py +4 -4
- android_env/wrappers/flat_interface_wrapper.py +5 -5
- android_env/wrappers/flat_interface_wrapper_test.py +7 -11
- android_env/wrappers/float_pixels_wrapper.py +9 -10
- android_env/wrappers/float_pixels_wrapper_test.py +3 -3
- android_env/wrappers/gym_wrapper.py +19 -13
- android_env/wrappers/gym_wrapper_test.py +3 -5
- android_env/wrappers/image_rescale_wrapper.py +18 -21
- android_env/wrappers/image_rescale_wrapper_test.py +25 -37
- android_env/wrappers/last_action_wrapper.py +16 -13
- android_env/wrappers/last_action_wrapper_test.py +44 -51
- android_env/wrappers/rate_limit_wrapper.py +6 -3
- android_env/wrappers/rate_limit_wrapper_test.py +22 -1
- android_env/wrappers/tap_action_wrapper.py +16 -17
- android_env/wrappers/tap_action_wrapper_test.py +51 -16
- {android_env-1.2.1.dist-info → android_env-1.2.3.dist-info}/METADATA +14 -18
- android_env-1.2.3.dist-info/RECORD +141 -0
- {android_env-1.2.1.dist-info → android_env-1.2.3.dist-info}/WHEEL +1 -1
- android_env/proto/raw_observation.proto +0 -39
- android_env/proto/raw_observation_pb2.py +0 -27
- android_env/proto/raw_observation_pb2_grpc.py +0 -4
- android_env-1.2.1.dist-info/RECORD +0 -81
- {android_env-1.2.1.dist-info → android_env-1.2.3.dist-info/licenses}/LICENSE +0 -0
- {android_env-1.2.1.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.
|
@@ -23,13 +23,17 @@ from unittest import mock
|
|
23
23
|
from absl.testing import absltest
|
24
24
|
from android_env.components import adb_call_parser
|
25
25
|
from android_env.components import adb_controller
|
26
|
+
from android_env.components import config_classes
|
26
27
|
from android_env.components.simulators.emulator import emulator_launcher
|
27
28
|
from android_env.components.simulators.emulator import emulator_simulator
|
29
|
+
from android_env.proto import state_pb2
|
28
30
|
import grpc
|
29
31
|
from PIL import Image
|
32
|
+
import portpicker
|
30
33
|
|
31
34
|
from android_env.proto import emulator_controller_pb2
|
32
35
|
from android_env.proto import emulator_controller_pb2_grpc
|
36
|
+
from android_env.proto import snapshot_service_pb2
|
33
37
|
|
34
38
|
|
35
39
|
class EmulatorSimulatorTest(absltest.TestCase):
|
@@ -47,21 +51,16 @@ class EmulatorSimulatorTest(absltest.TestCase):
|
|
47
51
|
|
48
52
|
self._grpc_channel = mock.create_autospec(grpc.Channel)
|
49
53
|
mock.patch.object(
|
50
|
-
grpc.aio, 'secure_channel',
|
51
|
-
return_value=self._grpc_channel).start()
|
54
|
+
grpc.aio, 'secure_channel', return_value=self._grpc_channel).start()
|
52
55
|
mock.patch.object(
|
53
|
-
grpc, 'secure_channel',
|
54
|
-
return_value=self._grpc_channel).start()
|
56
|
+
grpc, 'secure_channel', return_value=self._grpc_channel).start()
|
55
57
|
mock.patch.object(
|
56
58
|
grpc, 'local_channel_credentials',
|
57
59
|
return_value=self._grpc_channel).start()
|
58
60
|
self._mock_future = mock.create_autospec(grpc.Future)
|
59
61
|
mock.patch.object(
|
60
|
-
grpc, 'channel_ready_future',
|
61
|
-
|
62
|
-
mock.patch.object(
|
63
|
-
time, 'time',
|
64
|
-
return_value=12345).start()
|
62
|
+
grpc, 'channel_ready_future', return_value=self._mock_future).start()
|
63
|
+
mock.patch.object(time, 'time', return_value=12345).start()
|
65
64
|
|
66
65
|
mock.patch.object(
|
67
66
|
adb_controller, 'AdbController',
|
@@ -76,67 +75,110 @@ class EmulatorSimulatorTest(absltest.TestCase):
|
|
76
75
|
return_value=self._launcher).start()
|
77
76
|
|
78
77
|
def test_adb_device_name_not_empty(self):
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
78
|
+
config = config_classes.EmulatorConfig(
|
79
|
+
emulator_launcher=config_classes.EmulatorLauncherConfig(
|
80
|
+
grpc_port=1234, tmp_dir=self.create_tempdir().full_path
|
81
|
+
),
|
82
|
+
adb_controller=config_classes.AdbControllerConfig(
|
83
|
+
adb_path='/my/adb',
|
84
|
+
adb_server_port=5037,
|
85
|
+
),
|
86
|
+
)
|
87
|
+
simulator = emulator_simulator.EmulatorSimulator(config)
|
87
88
|
self.assertNotEmpty(simulator.adb_device_name())
|
88
89
|
|
89
90
|
@mock.patch.object(os.path, 'exists', autospec=True, return_value=True)
|
90
91
|
@mock.patch.object(builtins, 'open', autospec=True)
|
91
92
|
def test_logfile_path(self, mock_open, unused_mock_exists):
|
92
|
-
|
93
|
-
simulator = emulator_simulator.EmulatorSimulator(
|
94
|
-
tmp_dir=tmp_dir,
|
93
|
+
config = config_classes.EmulatorConfig(
|
95
94
|
logfile_path='fake/logfile/path',
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
95
|
+
emulator_launcher=config_classes.EmulatorLauncherConfig(
|
96
|
+
grpc_port=1234, tmp_dir=self.create_tempdir().full_path
|
97
|
+
),
|
98
|
+
adb_controller=config_classes.AdbControllerConfig(
|
99
|
+
adb_path='/my/adb',
|
100
|
+
adb_server_port=5037,
|
101
|
+
),
|
102
|
+
)
|
103
|
+
simulator = emulator_simulator.EmulatorSimulator(config)
|
101
104
|
mock_open.return_value.__enter__.return_value.read.return_value = (
|
102
105
|
'fake_logs'.encode('utf-8'))
|
103
106
|
logs = simulator.get_logs()
|
104
107
|
mock_open.assert_called_once_with('fake/logfile/path', 'rb')
|
105
108
|
self.assertEqual(logs, 'fake_logs')
|
106
109
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
+
@mock.patch.object(portpicker, 'is_port_free', return_value=True)
|
111
|
+
def test_grpc_port(self, unused_mock_portpicker):
|
112
|
+
|
113
|
+
launcher_config = config_classes.EmulatorLauncherConfig(
|
114
|
+
tmp_dir=self.create_tempdir().full_path
|
115
|
+
)
|
116
|
+
config = config_classes.EmulatorConfig(
|
117
|
+
emulator_launcher=launcher_config,
|
118
|
+
adb_controller=config_classes.AdbControllerConfig(
|
119
|
+
adb_path='/my/adb',
|
120
|
+
adb_server_port=5037,
|
121
|
+
),
|
122
|
+
)
|
123
|
+
simulator = emulator_simulator.EmulatorSimulator(config)
|
124
|
+
self.assertEqual(launcher_config.grpc_port, 8554)
|
125
|
+
|
126
|
+
@mock.patch.object(portpicker, 'is_port_free', return_value=False)
|
127
|
+
def test_grpc_port_unavailable(self, unused_mock_portpicker):
|
128
|
+
|
129
|
+
launcher_config = config_classes.EmulatorLauncherConfig(
|
130
|
+
tmp_dir=self.create_tempdir().full_path
|
131
|
+
)
|
132
|
+
config = config_classes.EmulatorConfig(
|
133
|
+
emulator_launcher=launcher_config,
|
134
|
+
adb_controller=config_classes.AdbControllerConfig(
|
135
|
+
adb_path='/my/adb',
|
136
|
+
adb_server_port=5037,
|
137
|
+
),
|
138
|
+
)
|
139
|
+
simulator = emulator_simulator.EmulatorSimulator(config)
|
140
|
+
self.assertNotEqual(launcher_config.grpc_port, 8554)
|
141
|
+
|
142
|
+
def test_launch_operation_order(self):
|
143
|
+
"""Makes sure that adb_controller is started before Emulator is launched."""
|
144
|
+
|
145
|
+
# Arrange.
|
110
146
|
call_order = []
|
111
|
-
self._adb_controller.init_server.side_effect = (
|
112
|
-
|
147
|
+
self._adb_controller.init_server.side_effect = lambda: call_order.append(
|
148
|
+
'init_server'
|
149
|
+
)
|
113
150
|
self._launcher.launch_emulator_process.side_effect = (
|
114
|
-
lambda
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
151
|
+
lambda: call_order.append('launch_emulator_process')
|
152
|
+
)
|
153
|
+
config = config_classes.EmulatorConfig(
|
154
|
+
emulator_launcher=config_classes.EmulatorLauncherConfig(
|
155
|
+
grpc_port=1234, tmp_dir=self.create_tempdir().full_path
|
156
|
+
),
|
157
|
+
adb_controller=config_classes.AdbControllerConfig(
|
158
|
+
adb_path='/my/adb',
|
159
|
+
adb_server_port=5037,
|
160
|
+
),
|
161
|
+
)
|
162
|
+
simulator = emulator_simulator.EmulatorSimulator(config)
|
163
|
+
|
164
|
+
# Act.
|
165
|
+
simulator.launch() # The simulator should launch and not crash.
|
166
|
+
|
167
|
+
# Assert.
|
168
|
+
# The adb server should be initialized before launching the emulator.
|
129
169
|
self.assertEqual(call_order, ['init_server', 'launch_emulator_process'])
|
130
170
|
|
131
171
|
def test_close(self):
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
172
|
+
config = config_classes.EmulatorConfig(
|
173
|
+
emulator_launcher=config_classes.EmulatorLauncherConfig(
|
174
|
+
grpc_port=1234, tmp_dir=self.create_tempdir().full_path
|
175
|
+
),
|
176
|
+
adb_controller=config_classes.AdbControllerConfig(
|
177
|
+
adb_path='/my/adb',
|
178
|
+
adb_server_port=5037,
|
179
|
+
),
|
180
|
+
)
|
181
|
+
simulator = emulator_simulator.EmulatorSimulator(config)
|
140
182
|
|
141
183
|
# The simulator should launch and not crash.
|
142
184
|
simulator.launch()
|
@@ -146,15 +188,36 @@ class EmulatorSimulatorTest(absltest.TestCase):
|
|
146
188
|
# resources.
|
147
189
|
simulator.close()
|
148
190
|
|
149
|
-
def
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
191
|
+
def test_value_error_if_launch_attempt_params_incorrect(self):
|
192
|
+
self.assertRaises(
|
193
|
+
ValueError,
|
194
|
+
emulator_simulator.EmulatorSimulator,
|
195
|
+
config=config_classes.EmulatorConfig(
|
196
|
+
emulator_launcher=config_classes.EmulatorLauncherConfig(
|
197
|
+
grpc_port=1234, tmp_dir=self.create_tempdir().full_path
|
198
|
+
),
|
199
|
+
adb_controller=config_classes.AdbControllerConfig(
|
200
|
+
adb_path='/my/adb',
|
201
|
+
adb_server_port=5037,
|
202
|
+
),
|
203
|
+
launch_n_times_without_reboot=2,
|
204
|
+
launch_n_times_without_reinstall=1,
|
205
|
+
),
|
206
|
+
)
|
207
|
+
|
208
|
+
def test_launch_attempt_reboot(self):
|
209
|
+
config = config_classes.EmulatorConfig(
|
210
|
+
emulator_launcher=config_classes.EmulatorLauncherConfig(
|
211
|
+
grpc_port=1234, tmp_dir=self.create_tempdir().full_path
|
212
|
+
),
|
213
|
+
adb_controller=config_classes.AdbControllerConfig(
|
214
|
+
adb_path='/my/adb',
|
215
|
+
adb_server_port=5037,
|
216
|
+
),
|
217
|
+
launch_n_times_without_reboot=1,
|
218
|
+
launch_n_times_without_reinstall=2,
|
219
|
+
)
|
220
|
+
simulator = emulator_simulator.EmulatorSimulator(config)
|
158
221
|
|
159
222
|
# The simulator should launch and not crash.
|
160
223
|
simulator.launch()
|
@@ -162,20 +225,82 @@ class EmulatorSimulatorTest(absltest.TestCase):
|
|
162
225
|
self._launcher.launch_emulator_process.assert_called_once()
|
163
226
|
self._launcher.reset_mock()
|
164
227
|
|
165
|
-
#
|
166
|
-
simulator.
|
228
|
+
# Launch attempt 2.
|
229
|
+
simulator.launch()
|
167
230
|
self._launcher.confirm_shutdown.assert_called_once()
|
231
|
+
self._launcher.close.assert_not_called()
|
232
|
+
self._launcher.launch_emulator_process.assert_called_once()
|
233
|
+
|
234
|
+
def test_launch_attempt_reinstall_after_zero_attempts(self):
|
235
|
+
config = config_classes.EmulatorConfig(
|
236
|
+
emulator_launcher=config_classes.EmulatorLauncherConfig(
|
237
|
+
grpc_port=1234, tmp_dir=self.create_tempdir().full_path
|
238
|
+
),
|
239
|
+
adb_controller=config_classes.AdbControllerConfig(
|
240
|
+
adb_path='/my/adb',
|
241
|
+
adb_server_port=5037,
|
242
|
+
),
|
243
|
+
launch_n_times_without_reboot=0,
|
244
|
+
launch_n_times_without_reinstall=0,
|
245
|
+
)
|
246
|
+
simulator = emulator_simulator.EmulatorSimulator(config)
|
247
|
+
|
248
|
+
# The simulator should not reboot or reinstall on its very first launch.
|
249
|
+
simulator.launch()
|
250
|
+
self._launcher.launch_emulator_process.assert_called_once()
|
251
|
+
self._launcher.confirm_shutdown.assert_not_called()
|
252
|
+
self._launcher.close.assert_not_called()
|
253
|
+
|
254
|
+
# Every subsequent attempt should reboot and reinstall.
|
255
|
+
self._launcher.reset_mock()
|
256
|
+
simulator.launch()
|
257
|
+
self._launcher.confirm_shutdown.assert_called_once()
|
258
|
+
self._launcher.close.assert_called_once() # Now this should `close()`.
|
259
|
+
self._launcher.launch_emulator_process.assert_called_once()
|
260
|
+
|
261
|
+
def test_launch_attempt_reinstall(self):
|
262
|
+
config = config_classes.EmulatorConfig(
|
263
|
+
emulator_launcher=config_classes.EmulatorLauncherConfig(
|
264
|
+
grpc_port=1234, tmp_dir=self.create_tempdir().full_path
|
265
|
+
),
|
266
|
+
adb_controller=config_classes.AdbControllerConfig(
|
267
|
+
adb_path='/my/adb',
|
268
|
+
adb_server_port=5037,
|
269
|
+
),
|
270
|
+
launch_n_times_without_reboot=1,
|
271
|
+
launch_n_times_without_reinstall=2,
|
272
|
+
)
|
273
|
+
simulator = emulator_simulator.EmulatorSimulator(config)
|
274
|
+
|
275
|
+
# The simulator should launch and not crash.
|
276
|
+
simulator.launch()
|
277
|
+
self._launcher.launch_emulator_process.assert_called_once()
|
278
|
+
|
279
|
+
# Launch attempt 2.
|
280
|
+
self._launcher.reset_mock()
|
281
|
+
simulator.launch()
|
282
|
+
self._launcher.confirm_shutdown.assert_called_once()
|
283
|
+
self._launcher.close.assert_not_called() # Reboots don't `close()`.
|
284
|
+
self._launcher.launch_emulator_process.assert_called_once()
|
285
|
+
|
286
|
+
# Launch attempt 3.
|
287
|
+
self._launcher.reset_mock()
|
288
|
+
simulator.launch()
|
289
|
+
self._launcher.confirm_shutdown.assert_called_once()
|
290
|
+
self._launcher.close.assert_called_once() # Now this should `close()`.
|
168
291
|
self._launcher.launch_emulator_process.assert_called_once()
|
169
292
|
|
170
293
|
def test_get_screenshot(self):
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
294
|
+
config = config_classes.EmulatorConfig(
|
295
|
+
emulator_launcher=config_classes.EmulatorLauncherConfig(
|
296
|
+
grpc_port=1234, tmp_dir=self.create_tempdir().full_path
|
297
|
+
),
|
298
|
+
adb_controller=config_classes.AdbControllerConfig(
|
299
|
+
adb_path='/my/adb',
|
300
|
+
adb_server_port=5037,
|
301
|
+
),
|
302
|
+
)
|
303
|
+
simulator = emulator_simulator.EmulatorSimulator(config)
|
179
304
|
|
180
305
|
# The simulator should launch and not crash.
|
181
306
|
simulator.launch()
|
@@ -191,15 +316,113 @@ class EmulatorSimulatorTest(absltest.TestCase):
|
|
191
316
|
# and it should have 3 channels (RGB).
|
192
317
|
self.assertEqual(screenshot.shape, (1234, 5678, 3))
|
193
318
|
|
319
|
+
def test_load_state(self):
|
320
|
+
config = config_classes.EmulatorConfig(
|
321
|
+
emulator_launcher=config_classes.EmulatorLauncherConfig(
|
322
|
+
grpc_port=1234, tmp_dir=self.create_tempdir().full_path
|
323
|
+
),
|
324
|
+
adb_controller=config_classes.AdbControllerConfig(
|
325
|
+
adb_path='/my/adb',
|
326
|
+
adb_server_port=5037,
|
327
|
+
),
|
328
|
+
)
|
329
|
+
simulator = emulator_simulator.EmulatorSimulator(config)
|
330
|
+
|
331
|
+
# The simulator should launch and not crash.
|
332
|
+
simulator.launch()
|
333
|
+
|
334
|
+
with mock.patch.object(
|
335
|
+
simulator, '_snapshot_stub', create_autospec=True
|
336
|
+
) as mock_snapshot_stub:
|
337
|
+
snapshot_list = snapshot_service_pb2.SnapshotList()
|
338
|
+
snapshot_list.snapshots.add(snapshot_id='snapshot_name_foo')
|
339
|
+
snapshot_list.snapshots.add(snapshot_id='snapshot_name_bar')
|
340
|
+
mock_snapshot_stub.ListSnapshots.return_value = snapshot_list
|
341
|
+
mock_snapshot_stub.LoadSnapshot.return_value = (
|
342
|
+
snapshot_service_pb2.SnapshotPackage(success=True)
|
343
|
+
)
|
344
|
+
load_response = simulator.load_state(
|
345
|
+
request=state_pb2.LoadStateRequest(
|
346
|
+
args={'snapshot_name': 'snapshot_name_foo'}
|
347
|
+
)
|
348
|
+
)
|
349
|
+
self.assertEqual(
|
350
|
+
load_response.status, state_pb2.LoadStateResponse.Status.OK
|
351
|
+
)
|
352
|
+
load_response = simulator.load_state(
|
353
|
+
request=state_pb2.LoadStateRequest(
|
354
|
+
args={'snapshot_name': 'snapshot_name_baz'}
|
355
|
+
)
|
356
|
+
)
|
357
|
+
self.assertEqual(
|
358
|
+
load_response.status, state_pb2.LoadStateResponse.Status.NOT_FOUND
|
359
|
+
)
|
360
|
+
mock_snapshot_stub.LoadSnapshot.return_value = (
|
361
|
+
snapshot_service_pb2.SnapshotPackage(success=False, err=b'error')
|
362
|
+
)
|
363
|
+
load_response = simulator.load_state(
|
364
|
+
request=state_pb2.LoadStateRequest(
|
365
|
+
args={'snapshot_name': 'snapshot_name_bar'}
|
366
|
+
)
|
367
|
+
)
|
368
|
+
self.assertEqual(
|
369
|
+
load_response.status, state_pb2.LoadStateResponse.Status.ERROR
|
370
|
+
)
|
371
|
+
self.assertEqual(load_response.error_message, 'error')
|
372
|
+
|
373
|
+
def test_save_state(self):
|
374
|
+
config = config_classes.EmulatorConfig(
|
375
|
+
emulator_launcher=config_classes.EmulatorLauncherConfig(
|
376
|
+
grpc_port=1234, tmp_dir=self.create_tempdir().full_path
|
377
|
+
),
|
378
|
+
adb_controller=config_classes.AdbControllerConfig(
|
379
|
+
adb_path='/my/adb',
|
380
|
+
adb_server_port=5037,
|
381
|
+
),
|
382
|
+
)
|
383
|
+
simulator = emulator_simulator.EmulatorSimulator(config)
|
384
|
+
|
385
|
+
# The simulator should launch and not crash.
|
386
|
+
simulator.launch()
|
387
|
+
|
388
|
+
with mock.patch.object(
|
389
|
+
simulator, '_snapshot_stub', create_autospec=True
|
390
|
+
) as mock_snapshot_stub:
|
391
|
+
mock_snapshot_stub.SaveSnapshot.return_value = (
|
392
|
+
snapshot_service_pb2.SnapshotPackage(success=True)
|
393
|
+
)
|
394
|
+
save_response = simulator.save_state(
|
395
|
+
request=state_pb2.SaveStateRequest(
|
396
|
+
args={'snapshot_name': 'snapshot_name_foo'}
|
397
|
+
)
|
398
|
+
)
|
399
|
+
self.assertEqual(
|
400
|
+
save_response.status, state_pb2.SaveStateResponse.Status.OK
|
401
|
+
)
|
402
|
+
mock_snapshot_stub.SaveSnapshot.return_value = (
|
403
|
+
snapshot_service_pb2.SnapshotPackage(success=False, err=b'error')
|
404
|
+
)
|
405
|
+
save_response = simulator.save_state(
|
406
|
+
request=state_pb2.SaveStateRequest(
|
407
|
+
args={'snapshot_name': 'snapshot_name_bar'}
|
408
|
+
)
|
409
|
+
)
|
410
|
+
self.assertEqual(
|
411
|
+
save_response.status, state_pb2.SaveStateResponse.Status.ERROR
|
412
|
+
)
|
413
|
+
self.assertEqual(save_response.error_message, 'error')
|
414
|
+
|
194
415
|
def test_send_touch(self):
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
416
|
+
config = config_classes.EmulatorConfig(
|
417
|
+
emulator_launcher=config_classes.EmulatorLauncherConfig(
|
418
|
+
grpc_port=1234, tmp_dir=self.create_tempdir().full_path
|
419
|
+
),
|
420
|
+
adb_controller=config_classes.AdbControllerConfig(
|
421
|
+
adb_path='/my/adb',
|
422
|
+
adb_server_port=5037,
|
423
|
+
),
|
424
|
+
)
|
425
|
+
simulator = emulator_simulator.EmulatorSimulator(config)
|
203
426
|
|
204
427
|
# The simulator should launch and not crash.
|
205
428
|
simulator.launch()
|
@@ -247,14 +470,16 @@ class EmulatorSimulatorTest(absltest.TestCase):
|
|
247
470
|
])
|
248
471
|
|
249
472
|
def test_send_key(self):
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
473
|
+
config = config_classes.EmulatorConfig(
|
474
|
+
emulator_launcher=config_classes.EmulatorLauncherConfig(
|
475
|
+
grpc_port=1234, tmp_dir=self.create_tempdir().full_path
|
476
|
+
),
|
477
|
+
adb_controller=config_classes.AdbControllerConfig(
|
478
|
+
adb_path='/my/adb',
|
479
|
+
adb_server_port=5037,
|
480
|
+
),
|
481
|
+
)
|
482
|
+
simulator = emulator_simulator.EmulatorSimulator(config)
|
258
483
|
|
259
484
|
# The simulator should launch and not crash.
|
260
485
|
simulator.launch()
|
@@ -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.
|
@@ -18,16 +18,16 @@
|
|
18
18
|
import random
|
19
19
|
import threading
|
20
20
|
import time
|
21
|
-
from typing import List, Optional, Tuple
|
22
21
|
|
23
22
|
from absl import logging
|
24
23
|
from android_env.components import adb_controller
|
24
|
+
from android_env.components import config_classes
|
25
25
|
from android_env.components import log_stream
|
26
26
|
from android_env.components.simulators import base_simulator
|
27
27
|
import numpy as np
|
28
28
|
|
29
29
|
|
30
|
-
class FakeStream
|
30
|
+
class FakeStream:
|
31
31
|
"""This class simulates the logs coming from ADB."""
|
32
32
|
|
33
33
|
def __init__(self):
|
@@ -77,12 +77,15 @@ class FakeLogStream(log_stream.LogStream):
|
|
77
77
|
class FakeAdbController(adb_controller.AdbController):
|
78
78
|
"""Fake adb controller for FakeSimulator."""
|
79
79
|
|
80
|
-
def execute_command(
|
81
|
-
|
82
|
-
|
80
|
+
def execute_command(
|
81
|
+
self,
|
82
|
+
args: list[str],
|
83
|
+
timeout: float | None = None,
|
84
|
+
device_specific: bool = True,
|
85
|
+
) -> bytes:
|
83
86
|
"""Returns fake output for adb commands."""
|
84
87
|
|
85
|
-
del timeout
|
88
|
+
del timeout, device_specific
|
86
89
|
|
87
90
|
# Fake "service is ready" output.
|
88
91
|
if args[:3] == ['shell', 'service', 'check']:
|
@@ -103,18 +106,10 @@ class FakeAdbController(adb_controller.AdbController):
|
|
103
106
|
class FakeSimulator(base_simulator.BaseSimulator):
|
104
107
|
"""FakeSimulator class."""
|
105
108
|
|
106
|
-
def __init__(self,
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
Args:
|
112
|
-
screen_dimensions: desired screen dimensions in pixels. This determines
|
113
|
-
the shape of the screenshots returned by get_screenshot().
|
114
|
-
**kwargs: other keyword arguments for the base class.
|
115
|
-
"""
|
116
|
-
super().__init__(**kwargs)
|
117
|
-
self._screen_dimensions = np.array(screen_dimensions)
|
109
|
+
def __init__(self, config: config_classes.FakeSimulatorConfig):
|
110
|
+
"""FakeSimulator class that can replace EmulatorSimulator in AndroidEnv."""
|
111
|
+
super().__init__(config)
|
112
|
+
self._screen_dimensions = np.array(config.screen_dimensions)
|
118
113
|
logging.info('Created FakeSimulator.')
|
119
114
|
|
120
115
|
def get_logs(self) -> str:
|
@@ -124,23 +119,20 @@ class FakeSimulator(base_simulator.BaseSimulator):
|
|
124
119
|
return 'fake_simulator'
|
125
120
|
|
126
121
|
def create_adb_controller(self):
|
127
|
-
return FakeAdbController()
|
122
|
+
return FakeAdbController(config_classes.AdbControllerConfig())
|
128
123
|
|
129
124
|
def create_log_stream(self) -> log_stream.LogStream:
|
130
125
|
return FakeLogStream()
|
131
126
|
|
132
|
-
def _restart_impl(self) -> None:
|
133
|
-
pass
|
134
|
-
|
135
127
|
def _launch_impl(self) -> None:
|
136
128
|
pass
|
137
129
|
|
138
|
-
def send_touch(self, touches:
|
130
|
+
def send_touch(self, touches: list[tuple[int, int, bool, int]]) -> None:
|
139
131
|
del touches
|
140
132
|
|
141
133
|
def send_key(self, keycode: np.int32, event_type: str) -> None:
|
142
134
|
del keycode, event_type
|
143
135
|
|
144
|
-
def
|
136
|
+
def _get_screenshot_impl(self) -> np.ndarray:
|
145
137
|
return np.random.randint(
|
146
138
|
low=0, high=255, size=(*self._screen_dimensions, 3), dtype=np.uint8)
|