blob: b29c5dd641b46a06034fe45f6cb9aa73f51da304 [file] [log] [blame]
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +01001#!/usr/bin/env python3
2
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +01003import os
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +01004import time
5from uiautomator import Device
Franz-Xaver Geigerb0f55422018-04-17 10:33:37 +02006import re
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +01007import sys
8import subprocess
9import pathlib
10
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010011
Borjan Tchakaloffd8445d32018-04-18 18:01:20 +020012VWS_CREDENTIALS = {
13 'user': 'fairphonetesting@gmail.com',
14 'password': 'aish3echi:uwaiSh'
15}
16
17
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010018PREBUILTS_PATH = '../../vendor/smartviser/viser/prebuilts/apk'
19
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +020020PREBUILT_PROXY_APK_PATTERN = (
21 'com.lunarlabs.panda.proxy-latest-sdk{sdk}-{flavour}.apk')
Franz-Xaver Geigerb3f7c982018-04-12 09:29:32 +020022
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010023PREBUILT_APKS = [
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +020024 'com.smartviser.demogame-latest.apk',
25 'com.lunarlabs.panda-latest.apk',
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010026]
27
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +020028FAIRPHONE_WIFI_NETWORKS = {
29 'Fairphone Guest': {'security': 'WPA/WPA2 PSK', 'password': 'fairwifi'},
30 'Fairphone DEV (2.4 GHz)': {
31 'security': 'WPA/WPA2 PSK', 'password': 'fdev@adm'},
32 'Fairphone DEV (5 GHz)': {
33 'security': 'WPA/WPA2 PSK', 'password': 'fdev@adm'},
34}
35
Franz-Xaver Geigerb0f55422018-04-17 10:33:37 +020036ADB_DEVICES_PATTERN = re.compile(r'^([a-z0-9-]+)\s+device$', flags=re.M)
37
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010038
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020039class HostCommandError(BaseException):
40 """An error happened while issuing a command on the host."""
41 def __init__(self, command, error_message):
42 self.command = command
43 self.error_message = error_message
44 message = 'Command `{}` failed: {}'.format(command, error_message)
45 super(HostCommandError, self).__init__(message)
46
47
48class DeviceCommandError(BaseException):
49 """An error happened while sending a command to a device."""
50 def __init__(self, serial, command, error_message):
51 self.serial = serial
52 self.command = command
53 self.error_message = error_message
54 message = 'Command `{}` failed on {}: {}'.format(
55 command, serial, error_message)
56 super(DeviceCommandError, self).__init__(message)
57
58
59def adb(*args, serial = None, raise_on_error = True):
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010060 """Run ADB command attached to serial.
61
62 Example:
63 >>> process = adb('shell', 'getprop', 'ro.build.fingerprint', serial='cc60c021')
64 >>> process.returncode
65 0
66 >>> process.stdout.strip()
67 'Fairphone/FP2/FP2:6.0.1/FP2-gms-18.02.0/FP2-gms-18.02.0:user/release-keys'
68
69 :param *args:
70 List of options to ADB (including command).
71 :param str serial:
72 Identifier for ADB connection to device.
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020073 :param raise_on_error bool:
74 Whether to raise a DeviceCommandError exception if the return code is
75 less than 0.
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010076 :returns subprocess.CompletedProcess:
77 Completed process.
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020078 :raises DeviceCommandError:
79 If the command failed.
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010080 """
81
82 # Make sure the adb server is started to avoid the infamous "out of date"
83 # message that pollutes stdout.
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020084 ret = subprocess.run(
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010085 ['adb', 'start-server'], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
86 universal_newlines=True)
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020087 if ret.returncode < 0:
88 if raise_on_error:
89 raise DeviceCommandError(
90 serial if serial else '??', str(args), ret.stderr)
91 else:
92 return None
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010093
94 command = ['adb']
95 if serial:
96 command += ['-s', serial]
97 if args:
98 command += list(args)
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020099 ret = subprocess.run(
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100100 command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
101 universal_newlines=True)
102
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200103 if raise_on_error and ret.returncode < 0:
104 raise DeviceCommandError(
105 serial if serial else '??', str(args), ret.stderr)
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100106
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200107 return ret
108
109
Franz-Xaver Geigerb0f55422018-04-17 10:33:37 +0200110def list_devices():
111 """List serial numbers of devices attached to adb.
112
113 Raises:
114 DeviceCommandError: If the underlying adb command failed.
115 """
116 process = adb('devices')
117 return ADB_DEVICES_PATTERN.findall(process.stdout)
118
119
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200120def aapt(*args, raise_on_error = True):
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100121 """Run an AAPT command.
122
123 :param *args:
124 The AAPT command with its options.
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200125 :param raise_on_error bool:
126 Whether to raise a DeviceCommandError exception if the return code is
127 less than 0.
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100128 :returns subprocess.CompletedProcess:
129 Completed process.
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200130 :raises HostCommandError:
131 If the command failed.
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100132 """
133 command = ['aapt']
134 if args:
135 command += list(args)
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200136 ret = subprocess.run(
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100137 command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
138 universal_newlines=True)
139
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200140 if raise_on_error and ret.returncode < 0:
141 raise HostCommandError(str(args), ret.stderr)
142
143 return ret
144
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100145
Borjan Tchakaloff64ec42b2018-02-07 11:33:15 -0800146def force_awake(serial, always=True):
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200147 """Force the device to stay awake.
148
149 Raises:
150 DeviceCommandError: If the underlying adb command failed.
151 """
152 adb('shell', 'svc power stayon {}'.format(
Borjan Tchakaloff64ec42b2018-02-07 11:33:15 -0800153 'true' if always else 'false'), serial=serial)
154
155
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200156def unlock(dut):
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200157 """Wake-up the device and unlock it.
158
159 Raises:
160 DeviceCommandError: If the underlying adb commands failed.
161 """
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200162 if not dut.info['screenOn']:
163 adb('shell', 'input keyevent KEYCODE_POWER', serial=dut.serial)
164 time.sleep(1)
165 # The KEYCODE_MENU input is enough to unlock a "swipe up to unlock"
166 # lockscreen on Android 6, but unfortunately not Android 7. So we use a
167 # swipe up (that depends on the screen resolution) instead.
168 adb('shell', 'input touchscreen swipe 930 880 930 380', serial=dut.serial)
Borjan Tchakaloff64ec42b2018-02-07 11:33:15 -0800169 time.sleep(1)
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200170 adb('shell', 'input keyevent KEYCODE_HOME', serial=dut.serial)
Borjan Tchakaloff64ec42b2018-02-07 11:33:15 -0800171
172
Franz-Xaver Geigerb3f7c982018-04-12 09:29:32 +0200173def getprop(serial, key):
174 """Get system property of device.
175
176 Example:
177 >>> getprop('167eb6e8', 'ro.build.id')
178 'FP2-gms-18.02.0'
179
180 :param str serial:
181 Identifier for ADB connection to device.
182 :param str key:
183 Key of property to get.
184 :returns str:
185 Value of system property.
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200186 :raise DeviceCommandError: If the underlying adb command failed.
Franz-Xaver Geigerb3f7c982018-04-12 09:29:32 +0200187 """
188 process = adb('shell', 'getprop', key, serial=serial)
189 return process.stdout.strip()
190
191
192def is_gms_device(serial):
193 """Test if device runs GMS or sibon.
194
195 Example:
196 >>> is_gms_device('167eb6e8')
197 True
198
199 :param str serial:
200 Identifier for ADB connection to device.
201 :returns bool:
202 True if device runs GMS, false otherwise.
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200203 :raise DeviceCommandError: If the underlying adb command failed.
Franz-Xaver Geigerb3f7c982018-04-12 09:29:32 +0200204 """
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200205 return (
206 getprop(serial, 'ro.build.id').startswith('FP2-gms-')
207 or getprop(serial, 'ro.build.version.incremental').startswith('gms-'))
Franz-Xaver Geigerb3f7c982018-04-12 09:29:32 +0200208
209
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100210def uninstall_apk(serial, filename, prebuilts_dir):
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200211 """Uninstall apk from prebuilts_dir on device.
212
213 Raises:
214 ValueError: If the package name could not be read from the apk.
215 DeviceCommandError: If the uninstall command failed.
216 """
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100217 ret = aapt('dump', 'badging', '{}/{}'.format(prebuilts_dir, filename))
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200218 package = None
219 for line in ret.stdout.splitlines():
220 if line.startswith('package'):
221 for token in line.split(' '):
222 if token.startswith('name='):
223 # Extract the package name out of the token
224 # (name='some.package.name')
225 package = token[6:-1]
226 break
227 if not package:
228 raise ValueError('Could not find package of app `{}`'.format(
229 filename))
230
231 adb('uninstall', package, serial=serial)
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100232
233
Borjan Tchakaloffd2c92ce2018-08-24 17:13:57 +0200234def install_apk(dut, filename, prebuilts_dir):
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200235 """Install apk from prebuilts_dir on device.
236
237 Raises:
238 DeviceCommandError: If the install command failed.
239 """
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100240 path = os.path.join(prebuilts_dir, filename)
Borjan Tchakaloffd2c92ce2018-08-24 17:13:57 +0200241 command = ['install', '-r']
242 if dut.sdk >= 23:
243 # From Marshmallow onwards, adb has a flag to grant default permissions
244 command.append('-g')
245 adb(*command, path, serial=dut.serial)
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100246
247
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200248def configure_wifi_networks(dut, networks):
249 """Configure Wi-Fi networks.
250
251 The `networks` parameters is a list of networks to configure hashed by
252 their SSID. Each network value should have the following format:
253 - security (str): The security value as can be found in the Wi-Fi
254 settings dialog. Common values are 'None' and 'WPA/WPA2 PSK'.
255 - password (str, optional): The network password if the security is
256 'WPA/WPA2 PSK'.
257
258 Parameters:
259 dut (Device): The device object.
260 networks (dict(dict(str))): The list of networks to configure.
261 Raises:
262 DeviceCommandError: If the UI automation fails.
263 """
264 # Open the Wi-Fi settings
265 adb('shell', ('am start -a android.settings.WIFI_SETTINGS '
266 '--activity-clear-task'), serial=dut.serial)
267
268 # Make sure Wi-Fi is enabled
269 wifi_enabler = dut(text='OFF',
270 resourceId='com.android.settings:id/switch_widget')
271 if wifi_enabler.exists:
272 wifi_enabler.click()
273
274 # Check for registered networks
275 registered_networks = set()
Borjan Tchakaloff1d83e562018-05-16 18:47:04 +0200276 dut(description='More options').click.wait()
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200277 time.sleep(1)
278 saved_networks = dut(text='Saved networks')
279 if saved_networks.exists:
Borjan Tchakaloff1d83e562018-05-16 18:47:04 +0200280 saved_networks.click.wait()
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200281 for ssid in networks.keys():
282 if dut(text=ssid).exists:
283 registered_networks.add(ssid)
284 dut.press.back()
285
286 missing_networks = networks.keys() - registered_networks
287
288 for ssid in registered_networks:
289 print('Ignoring `{}` Wi-Fi network, already configured.'.format(ssid))
290
291 for ssid in missing_networks:
292 print('Configuring `{}` Wi-Fi network…'.format(ssid))
293
Borjan Tchakaloff1d83e562018-05-16 18:47:04 +0200294 dut(description='More options').click.wait()
295 dut(text='Add network').click.wait()
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200296 dut(resourceId='com.android.settings:id/ssid') \
297 .set_text(ssid)
298 dut(resourceId='com.android.settings:id/security') \
299 .click()
300 dut(text=networks[ssid]['security']) \
301 .click()
302 password_field = dut(resourceId='com.android.settings:id/password')
303 if 'password' in networks[ssid] and networks[ssid]['password']:
304 if not password_field.exists:
305 dut(text='Cancel').click()
306 raise DeviceCommandError(dut, 'UI: add Wi-Fi',
307 'missing password field')
308 password_field.set_text(networks[ssid]['password'])
309 elif password_field.exists:
310 dut(text='Cancel').click()
311 raise DeviceCommandError(dut, 'UI: add Wi-Fi',
312 'missing password data')
313 save_button = dut(text='Save')
314 if not save_button.click():
315 dut(text='Cancel').click()
316 raise DeviceCommandError(dut, 'UI: add Wi-Fi',
317 'could not save network')
318
319 # Force the Wi-Fi on and off to pick the best network available
320 dut(text='ON', resourceId='com.android.settings:id/switch_widget').click()
321 dut(text='OFF', resourceId='com.android.settings:id/switch_widget').click()
322
323 # Leave the settings
324 dut.press.back()
325
326
Karsten Tauscheb36529f2019-03-02 14:13:29 +0100327def disable_privacy_impact_popup(dut):
328 """Disable Privacy Impact popup on Android 5.
329
330 This simplifies UI automation. Disabling the feature globally is more robust
331 than clicking through the the Privacy Impact screen per app.
332 """
333 print('Disabling the Privacy Impact screen…')
334 adb('shell',
335 ('am start -a android.intent.action.MAIN '
336 'com.fairphone.privacyimpact/.PrivacyImpactPreferenceActivity'),
337 serial=dut.serial
338 )
339 disable_privacy_impact_checkbox = dut(className='android.widget.CheckBox')
340 if not disable_privacy_impact_checkbox.checked:
341 disable_privacy_impact_checkbox.click()
342
343
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200344def get_proxy_apk(android_sdk, flavour):
345 if android_sdk >= 24:
346 return PREBUILT_PROXY_APK_PATTERN.format(sdk=24, flavour=flavour)
347 else:
348 return PREBUILT_PROXY_APK_PATTERN.format(sdk=19, flavour=flavour)
349
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100350# Prepare the DUT
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200351def prepare_dut(dut, scenarios_dir, data_dir, prebuilts_dir):
352 flavour = 'gms' if is_gms_device(dut.serial) else 'sibon'
353 proxy_apk = get_proxy_apk(dut.sdk, flavour)
Franz-Xaver Geigerb3f7c982018-04-12 09:29:32 +0200354
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100355 # Uninstall the smartviser apps
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200356 for app in PREBUILT_APKS + [proxy_apk]:
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200357 print('Uninstalling `{}`…'.format(app))
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200358 uninstall_apk(dut.serial, app, prebuilts_dir)
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100359
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100360 # Copy the scenarios
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200361 print('Pushing scenarios from `{}`…'.format(scenarios_dir))
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200362 adb('push', scenarios_dir, '/sdcard/viser', serial=dut.serial)
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100363
364 # Copy the scenarios data
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200365 print('Pushing scenarios data from `{}`…'.format(data_dir))
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200366 adb('push', data_dir, '/sdcard/viser/data', serial=dut.serial)
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100367
Franz-Xaver Geigerb3f7c982018-04-12 09:29:32 +0200368 # Install the smartviser apps (starting with the proxy app)
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200369 for app in [proxy_apk] + PREBUILT_APKS:
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200370 print('Installing `{}`…'.format(app))
Borjan Tchakaloffd2c92ce2018-08-24 17:13:57 +0200371 install_apk(dut, app, prebuilts_dir)
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100372
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100373
374# Grant the permissions through the UI
375def configure_perms(dut):
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100376 # Input the credentials
377 dut(resourceId='android:id/content') \
378 .child(text='Username') \
379 .child(className='android.widget.EditText') \
Borjan Tchakaloffd8445d32018-04-18 18:01:20 +0200380 .set_text(VWS_CREDENTIALS['user'])
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100381 dut(resourceId='android:id/content') \
382 .child(text='Password') \
383 .child(className='android.widget.EditText') \
Borjan Tchakaloffd8445d32018-04-18 18:01:20 +0200384 .set_text(VWS_CREDENTIALS['password'])
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100385
386 # Sign in
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200387 signin_label = 'SIGN IN' if dut.sdk >= 24 else 'Sign in'
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100388 dut(resourceId='android:id/content') \
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200389 .child(text=signin_label, className='android.widget.Button') \
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100390 .click()
391
392def configure_sms(dut):
393 # TODO wait for the connection to be established and time-out
394 prompt = dut(resourceId='android:id/content') \
395 .child(text='Viser must be your SMS app to send messages')
396 while not prompt.exists:
397 time.sleep(1)
398
399 # Make viser the default SMS app
400 dut(resourceId='android:id/content') \
401 .child_by_text('Viser must be your SMS app to send messages',
402 className='android.widget.LinearLayout') \
403 .child(text='OK', className='android.widget.Button') \
404 .click()
405
406 dut(resourceId='android:id/content') \
407 .child_by_text('Change SMS app?', className='android.widget.LinearLayout') \
408 .child(text='Yes', className='android.widget.Button') \
409 .click()
410
411def configure_settings(dut):
412 # Set the e-mail account
413 dut(text='Settings', className='android.widget.TextView') \
414 .click()
415 dut(resourceId='android:id/list') \
416 .child_by_text('User settings', className='android.widget.LinearLayout') \
417 .click()
418 dut(resourceId='android:id/list') \
419 .child_by_text('Email account', className='android.widget.LinearLayout') \
420 .click()
421 prompt = dut(resourceId='android:id/content') \
422 .child_by_text('Email account', className='android.widget.LinearLayout')
423 prompt.child(resourceId='android:id/edit') \
424 .set_text('fairphone.viser@gmail.com')
425 prompt.child(text='OK', className='android.widget.Button') \
426 .click()
427 dut(resourceId='android:id/list') \
428 .child_by_text('Email password', className='android.widget.LinearLayout') \
429 .click()
430 dut(text='Password :') \
431 .child(className='android.widget.EditText') \
432 .set_text('fairphoneviser2017')
433 dut(description='OK', className='android.widget.TextView') \
434 .click()
435 dut.press.back()
436 dut.press.back()
437
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100438
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100439def deploy():
440 serials = []
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100441
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100442 if len(sys.argv) > 1:
443 serials.append(sys.argv[1])
444 else:
Franz-Xaver Geigerb0f55422018-04-17 10:33:37 +0200445 serials = list_devices()
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100446
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100447 for serial in serials:
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200448 print('Configuring device {}…'.format(serial))
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100449
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100450 dut = Device(serial)
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200451 # Work around the not-so-easy Device class
452 dut.serial = serial
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200453 # Cache the Android SDK version (dut.info fetches system properties)
454 dut.sdk = dut.info['sdkInt']
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100455
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200456 try:
457 # Make sure the screen stays on - we're going to use UI automation
458 force_awake(serial)
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200459 unlock(dut)
Borjan Tchakaloff64ec42b2018-02-07 11:33:15 -0800460
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200461 # Configure common Fairphone Wi-Fi networks
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200462 if dut.sdk < 24:
463 configure_wifi_networks(dut, FAIRPHONE_WIFI_NETWORKS)
464 else:
465 print('Uh oh, the device is running Android SDK {} on which we '
466 'do not deploy Wi-Fi networks yet.'.format(dut.sdk))
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200467
Karsten Tauscheb36529f2019-03-02 14:13:29 +0100468 # Disable Privacy Impact popup on Android 5.
469 if dut.sdk <= 22:
470 disable_privacy_impact_popup(dut)
471
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200472 # Push the scenarios, their data, and install the apps
473 prepare_dut(
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200474 dut, '../scenarios', '../scenarios-data', PREBUILTS_PATH)
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100475
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200476 # Start the viser app
477 adb(
Franz-Xaver Geiger223ae752018-02-19 14:54:08 +0100478 'shell', 'monkey', '-p', 'com.lunarlabs.panda', '-c',
479 'android.intent.category.LAUNCHER', '1', serial=serial)
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100480
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200481 configure_perms(dut)
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100482
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200483 # TODO DO NOT DO THE FOLLOWING IF NO SIM CARD IS IN THE DUT
484 # time.sleep(10)
485 # configure_sms(dut)
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100486
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200487 configure_settings(dut)
488 except (HostCommandError, DeviceCommandError) as e:
489 print('ERROR {}'.format(e), file=sys.stderr)
490 finally:
491 try:
492 # Leave the device alone now
493 force_awake(serial, always=False)
494 except DeviceCommandError as e:
495 print('WARNING {}'.format(e), file=sys.stderr)
Borjan Tchakaloff64ec42b2018-02-07 11:33:15 -0800496
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100497
498if __name__ == '__main__':
499 deploy()