blob: 57a9c7bd352482c7a24377389b3569917c03bb7d [file] [log] [blame]
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +01001#!/usr/bin/env python3
2
Borjan Tchakaloff31c37e02020-02-07 14:03:27 +01003import logging
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +01004import pathlib
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +01005import re
6import subprocess
7import sys
8import time
9
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +010010import uiautomator
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010011
12VWS_CREDENTIALS = {"user": "fairphonetesting@gmail.com", "password": "aish3echi:uwaiSh"}
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +010013
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010014
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010015PREBUILTS_PATH = "../../vendor/smartviser/viser/prebuilts/apk"
Borjan Tchakaloffd8445d32018-04-18 18:01:20 +020016
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010017PREBUILT_PROXY_APK_PATTERN = "com.lunarlabs.panda.proxy-latest-sdk{sdk}-{flavour}.apk"
Borjan Tchakaloffd8445d32018-04-18 18:01:20 +020018
Borjan Tchakaloff31c37e02020-02-07 14:03:27 +010019
20_LOG = logging.getLogger(__name__)
21
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010022PREBUILT_APKS = ["com.smartviser.demogame-latest.apk", "com.lunarlabs.panda-latest.apk"]
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010023
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010024ADB_DEVICES_PATTERN = re.compile(r"^([a-z0-9-]+)\s+device$", flags=re.M)
Franz-Xaver Geigerb0f55422018-04-17 10:33:37 +020025
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010026
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020027class HostCommandError(BaseException):
28 """An error happened while issuing a command on the host."""
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010029
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020030 def __init__(self, command, error_message):
31 self.command = command
32 self.error_message = error_message
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010033 message = "Command `{}` failed: {}".format(command, error_message)
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020034 super(HostCommandError, self).__init__(message)
35
36
37class DeviceCommandError(BaseException):
38 """An error happened while sending a command to a device."""
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010039
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020040 def __init__(self, serial, command, error_message):
41 self.serial = serial
42 self.command = command
43 self.error_message = error_message
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010044 message = "Command `{}` failed on {}: {}".format(command, serial, error_message)
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020045 super(DeviceCommandError, self).__init__(message)
46
47
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010048def adb(*args, serial=None, raise_on_error=True):
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010049 """Run ADB command attached to serial.
50
51 Example:
52 >>> process = adb('shell', 'getprop', 'ro.build.fingerprint', serial='cc60c021')
53 >>> process.returncode
54 0
55 >>> process.stdout.strip()
56 'Fairphone/FP2/FP2:6.0.1/FP2-gms-18.02.0/FP2-gms-18.02.0:user/release-keys'
57
58 :param *args:
59 List of options to ADB (including command).
60 :param str serial:
61 Identifier for ADB connection to device.
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020062 :param raise_on_error bool:
63 Whether to raise a DeviceCommandError exception if the return code is
64 less than 0.
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010065 :returns subprocess.CompletedProcess:
66 Completed process.
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020067 :raises DeviceCommandError:
68 If the command failed.
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010069 """
70
71 # Make sure the adb server is started to avoid the infamous "out of date"
72 # message that pollutes stdout.
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020073 ret = subprocess.run(
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010074 ["adb", "start-server"],
75 stdout=subprocess.PIPE,
76 stderr=subprocess.PIPE,
77 universal_newlines=True,
78 )
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020079 if ret.returncode < 0:
80 if raise_on_error:
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010081 raise DeviceCommandError(serial if serial else "??", str(args), ret.stderr)
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020082 else:
83 return None
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010084
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010085 command = ["adb"]
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010086 if serial:
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010087 command += ["-s", serial]
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010088 if args:
89 command += list(args)
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020090 ret = subprocess.run(
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010091 command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True
92 )
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010093
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020094 if raise_on_error and ret.returncode < 0:
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010095 raise DeviceCommandError(serial if serial else "??", str(args), ret.stderr)
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010096
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020097 return ret
98
99
Franz-Xaver Geigerb0f55422018-04-17 10:33:37 +0200100def list_devices():
101 """List serial numbers of devices attached to adb.
102
103 Raises:
104 DeviceCommandError: If the underlying adb command failed.
105 """
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100106 process = adb("devices")
Franz-Xaver Geigerb0f55422018-04-17 10:33:37 +0200107 return ADB_DEVICES_PATTERN.findall(process.stdout)
108
109
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100110def aapt(*args, raise_on_error=True):
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100111 """Run an AAPT command.
112
113 :param *args:
114 The AAPT command with its options.
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200115 :param raise_on_error bool:
116 Whether to raise a DeviceCommandError exception if the return code is
117 less than 0.
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100118 :returns subprocess.CompletedProcess:
119 Completed process.
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200120 :raises HostCommandError:
121 If the command failed.
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100122 """
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100123 command = ["aapt"]
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100124 if args:
125 command += list(args)
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200126 ret = subprocess.run(
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100127 command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True
128 )
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100129
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200130 if raise_on_error and ret.returncode < 0:
131 raise HostCommandError(str(args), ret.stderr)
132
133 return ret
134
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100135
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100136def disable_privacy_impact_popup(device):
Karsten Tauscheb36529f2019-03-02 14:13:29 +0100137 """Disable Privacy Impact popup on Android 5.
138
139 This simplifies UI automation. Disabling the feature globally is more robust
140 than clicking through the the Privacy Impact screen per app.
141 """
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100142 print("Disabling the Privacy Impact screen…")
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100143 device.adb(
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100144 "shell",
145 (
146 "am start -a android.intent.action.MAIN "
147 "com.fairphone.privacyimpact/.PrivacyImpactPreferenceActivity"
148 ),
Karsten Tauscheb36529f2019-03-02 14:13:29 +0100149 )
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100150 disable_privacy_impact_checkbox = device.ui(className="android.widget.CheckBox")
Karsten Tauscheb36529f2019-03-02 14:13:29 +0100151 if not disable_privacy_impact_checkbox.checked:
152 disable_privacy_impact_checkbox.click()
153
154
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200155def get_proxy_apk(android_sdk, flavour):
156 if android_sdk >= 24:
157 return PREBUILT_PROXY_APK_PATTERN.format(sdk=24, flavour=flavour)
158 else:
159 return PREBUILT_PROXY_APK_PATTERN.format(sdk=19, flavour=flavour)
160
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100161
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100162# Prepare the DUT
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100163def prepare_dut(device, scenarios_dir, data_dir, prebuilts_dir):
164 flavour = "gms" if device.is_gms_device() else "sibon"
165 proxy_apk = get_proxy_apk(device.sdk, flavour)
166 prebuilts_dir = pathlib.Path(prebuilts_dir)
Franz-Xaver Geigerb3f7c982018-04-12 09:29:32 +0200167
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100168 # Uninstall the smartviser apps
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200169 for app in PREBUILT_APKS + [proxy_apk]:
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100170 print("Uninstalling `{}`…".format(app))
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100171 device.uninstall(prebuilts_dir / app)
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100172
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100173 # Copy the scenarios
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100174 print("Pushing scenarios from `{}`…".format(scenarios_dir))
Borjan Tchakaloffaafa2262020-02-07 11:53:07 +0100175 device.push(scenarios_dir, pathlib.Path("/sdcard/Viser"))
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100176
177 # Copy the scenarios data
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100178 print("Pushing scenarios data from `{}`…".format(data_dir))
Borjan Tchakaloffaafa2262020-02-07 11:53:07 +0100179 device.push(data_dir, pathlib.Path("/sdcard/Viser/Data"))
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100180
Franz-Xaver Geigerb3f7c982018-04-12 09:29:32 +0200181 # Install the smartviser apps (starting with the proxy app)
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200182 for app in [proxy_apk] + PREBUILT_APKS:
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100183 print("Installing `{}`…".format(app))
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100184 device.install(prebuilts_dir / app)
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100185
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100186
187# Grant the permissions through the UI
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100188def configure_perms(device):
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100189 # Input the credentials
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100190 device.ui(resourceId="android:id/content").child(text="Username").child(
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100191 className="android.widget.EditText"
192 ).set_text(VWS_CREDENTIALS["user"])
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100193 device.ui(resourceId="android:id/content").child(text="Password").child(
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100194 className="android.widget.EditText"
195 ).set_text(VWS_CREDENTIALS["password"])
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100196
197 # Sign in
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100198 signin_label = "SIGN IN" if device.sdk >= 24 else "Sign in"
199 device.ui(resourceId="android:id/content").child(
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100200 text=signin_label, className="android.widget.Button"
201 ).click()
202
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100203
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100204def configure_settings(device):
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100205 # Set the e-mail account
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100206 device.ui(text="Settings", className="android.widget.TextView").click()
207 device.ui(resourceId="android:id/list").child_by_text(
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100208 "User settings", className="android.widget.LinearLayout"
209 ).click()
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100210 device.ui(resourceId="android:id/list").child_by_text(
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100211 "Email account", className="android.widget.LinearLayout"
212 ).click()
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100213 prompt = device.ui(resourceId="android:id/content").child_by_text(
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100214 "Email account", className="android.widget.LinearLayout"
215 )
216 prompt.child(resourceId="android:id/edit").set_text("fairphone.viser@gmail.com")
217 prompt.child(text="OK", className="android.widget.Button").click()
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100218 device.ui(resourceId="android:id/list").child_by_text(
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100219 "Email password", className="android.widget.LinearLayout"
220 ).click()
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100221 device.ui(text="Password :").child(className="android.widget.EditText").set_text(
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100222 "fairphoneviser2017"
223 )
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100224 device.ui(description="OK", className="android.widget.TextView").click()
225 device.ui.press.back()
226 device.ui.press.back()
227
228
229class DeviceUnderTest:
230 """An Android device under test."""
231
232 serial: str
233 """The device serial number (adb/fastboot)."""
234 sdk: int
235 """The Android SDK version number."""
236 ui: uiautomator.Device
237 """The UI Automator handle piloting the device."""
238
239 def __init__(self, serial: str):
240 self.serial = serial
241 self.ui = uiautomator.Device(serial)
242
243 # Cache the Android SDK version
244 self.sdk = self.ui.info["sdkInt"]
245
246 def adb(self, *args) -> subprocess.CompletedProcess:
247 """Execute an adb command on this device.
248
249 :returns: The completed process.
250 :raise DeviceCommandError: If the underlying adb command failed.
251 """
252 return adb(*args, serial=self.serial)
253
254 def force_awake(self, always=True) -> None:
255 """Force the device to stay awake.
256
257 :raise DeviceCommandError: If the underlying adb command failed.
258 """
259 self.adb("shell", "svc power stayon {}".format("true" if always else "false"))
260
261 def unlock(self) -> None:
262 """Wake-up the device and unlock it.
263
264 :raise DeviceCommandError: If the underlying adb commands failed.
265 """
266 if not self.ui.info["screenOn"]:
267 self.adb("shell", "input keyevent KEYCODE_POWER")
268 time.sleep(1)
269 # The KEYCODE_MENU input is enough to unlock a "swipe up to unlock"
270 # lockscreen on Android 6, but unfortunately not Android 7. So we use a
271 # swipe up (that depends on the screen resolution) instead.
272 self.adb("shell", "input touchscreen swipe 930 880 930 380")
273 time.sleep(1)
274 self.adb("shell", "input keyevent KEYCODE_HOME")
275
276 def getprop(self, key: str) -> str:
277 """Get a system property.
278
279 Example:
280 >>> self.getprop('ro.build.id')
281 'FP2-gms-18.02.0'
282
283 :param key: Key of property to get.
284 :returns: Value of system property.
285 :raise DeviceCommandError: If the underlying adb command failed.
286 """
287 process = self.adb("shell", "getprop", key)
288 return process.stdout.strip()
289
290 def is_gms_device(self) -> bool:
291 """Whether the device runs GMS or sibon.
292
293 Example:
294 >>> self.is_gms_device()
295 True
296
297 :returns: True if device runs GMS, false otherwise.
298 :raise DeviceCommandError: If the underlying adb command failed.
299 """
300 return self.getprop("ro.build.id").startswith("FP2-gms-") or self.getprop(
301 "ro.build.version.incremental"
302 ).startswith("gms-")
303
304 def uninstall(self, apk: pathlib.Path) -> None:
305 """Uninstall an app from an APK file.
306
307 :raise ValueError: If the package name could not be read from the apk.
308 :raise DeviceCommandError: If the uninstall command failed.
309 """
310 ret = aapt("dump", "badging", str(apk))
311 package = None
312 for line in ret.stdout.splitlines():
313 if line.startswith("package"):
314 for token in line.split(" "):
315 if token.startswith("name="):
316 # Extract the package name out of the token
317 # (name='some.package.name')
318 package = token[6:-1]
319 break
320 if not package:
321 raise ValueError("Could not find package of app `{}`".format(apk.name))
322
323 self.adb("uninstall", package)
324
325 def install(self, apk: pathlib.Path) -> None:
326 """Install an app from an APK file.
327
328 :raise DeviceCommandError: If the install command failed.
329 """
330 command = ["install", "-r"]
331 if self.sdk >= 23:
332 # From Marshmallow onwards, adb has a flag to grant default permissions
333 command.append("-g")
334
335 self.adb(*command, str(apk))
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100336
Borjan Tchakaloffaafa2262020-02-07 11:53:07 +0100337 def push(self, source: pathlib.Path, target: pathlib.Path) -> None:
338 """Push a file or directory to the device.
339
340 The target directory (if the source is a directory), or its
341 parent (if the source if a file) will be created on the device,
342 always.
343
344 :raise DeviceCommandError: If the push command failed.
345 """
346 if source.is_dir():
347 # `adb push` skips empty directories so we have to manually create the
348 # target directory itself.
349 self.adb("shell", "mkdir", "-p", str(target))
350 # `adb push` expects the target to be the host directory not the target
351 # directory itself. So we'll just copy the source directory content instead.
352 sources = [str(child) for child in source.iterdir()]
353 self.adb("push", *sources, str(target))
354 else:
355 self.adb("shell", "mkdir", "-p", str(target.parent))
356 self.adb("push", str(source), str(target))
357
358 def remove(self, target: pathlib.Path, *, recurse: bool = False) -> None:
359 """Remove a file or directory from the device.
360
361 :raise DeviceCommandError: If the remove command failed.
362 """
363 command = ["shell", "rm", "-f"]
364 if recurse:
365 command.append("-r")
366 command.append(str(target))
367 self.adb(*command)
368
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100369
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100370def deploy():
371 serials = []
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100372
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100373 if len(sys.argv) > 1:
374 serials.append(sys.argv[1])
375 else:
Franz-Xaver Geigerb0f55422018-04-17 10:33:37 +0200376 serials = list_devices()
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100377
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100378 for serial in serials:
Borjan Tchakaloff31c37e02020-02-07 14:03:27 +0100379 _LOG.info("Deploy to device %s", serial)
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100380
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100381 device = DeviceUnderTest(serial)
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200382 try:
383 # Make sure the screen stays on - we're going to use UI automation
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100384 device.force_awake()
385 device.unlock()
Borjan Tchakaloff64ec42b2018-02-07 11:33:15 -0800386
Karsten Tauscheb36529f2019-03-02 14:13:29 +0100387 # Disable Privacy Impact popup on Android 5.
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100388 if device.sdk <= 22:
389 disable_privacy_impact_popup(device)
Karsten Tauscheb36529f2019-03-02 14:13:29 +0100390
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200391 # Push the scenarios, their data, and install the apps
Borjan Tchakaloffaafa2262020-02-07 11:53:07 +0100392 prepare_dut(
393 device,
394 pathlib.Path("../scenarios"),
395 pathlib.Path("../scenarios-data"),
396 PREBUILTS_PATH,
397 )
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100398
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200399 # Start the viser app
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100400 device.adb(
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100401 "shell",
402 "monkey",
403 "-p",
404 "com.lunarlabs.panda",
405 "-c",
406 "android.intent.category.LAUNCHER",
407 "1",
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100408 )
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100409
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100410 configure_perms(device)
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100411
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100412 configure_settings(device)
Borjan Tchakaloff31c37e02020-02-07 14:03:27 +0100413 except (HostCommandError, DeviceCommandError, uiautomator.JsonRPCError):
414 _LOG.error("Failed to execute deployment", exc_info=True)
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200415 finally:
416 try:
417 # Leave the device alone now
Borjan Tchakaloff1e841d82020-01-24 16:25:50 +0100418 device.force_awake(always=False)
Borjan Tchakaloff31c37e02020-02-07 14:03:27 +0100419 except DeviceCommandError:
420 _LOG.warning("Failed to tear down device", exc_info=True)
Borjan Tchakaloff64ec42b2018-02-07 11:33:15 -0800421
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100422
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100423if __name__ == "__main__":
Borjan Tchakaloff31c37e02020-02-07 14:03:27 +0100424 logging.basicConfig(
425 format="%(asctime)-15s:%(levelname)s:%(message)s", level=logging.INFO
426 )
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100427 deploy()