blob: a0a0b98dc8304369700e3f9e3eb0bfd11bcacf03 [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 pathlib
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +01005import re
6import subprocess
7import sys
8import time
9
10from uiautomator import Device
11
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 Tchakaloff7d4f6152020-01-24 15:41:00 +010019PREBUILT_APKS = ["com.smartviser.demogame-latest.apk", "com.lunarlabs.panda-latest.apk"]
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010020
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +020021FAIRPHONE_WIFI_NETWORKS = {
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010022 "Fairphone Guest": {"security": "WPA/WPA2 PSK", "password": "fairwifi"},
23 "Fairphone DEV (2.4 GHz)": {"security": "WPA/WPA2 PSK", "password": "fdev@adm"},
24 "Fairphone DEV (5 GHz)": {"security": "WPA/WPA2 PSK", "password": "fdev@adm"},
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +020025}
26
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010027ADB_DEVICES_PATTERN = re.compile(r"^([a-z0-9-]+)\s+device$", flags=re.M)
Franz-Xaver Geigerb0f55422018-04-17 10:33:37 +020028
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010029
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020030class HostCommandError(BaseException):
31 """An error happened while issuing a command on the host."""
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010032
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020033 def __init__(self, command, error_message):
34 self.command = command
35 self.error_message = error_message
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010036 message = "Command `{}` failed: {}".format(command, error_message)
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020037 super(HostCommandError, self).__init__(message)
38
39
40class DeviceCommandError(BaseException):
41 """An error happened while sending a command to a device."""
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010042
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020043 def __init__(self, serial, command, error_message):
44 self.serial = serial
45 self.command = command
46 self.error_message = error_message
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010047 message = "Command `{}` failed on {}: {}".format(command, serial, error_message)
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020048 super(DeviceCommandError, self).__init__(message)
49
50
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010051def adb(*args, serial=None, raise_on_error=True):
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010052 """Run ADB command attached to serial.
53
54 Example:
55 >>> process = adb('shell', 'getprop', 'ro.build.fingerprint', serial='cc60c021')
56 >>> process.returncode
57 0
58 >>> process.stdout.strip()
59 'Fairphone/FP2/FP2:6.0.1/FP2-gms-18.02.0/FP2-gms-18.02.0:user/release-keys'
60
61 :param *args:
62 List of options to ADB (including command).
63 :param str serial:
64 Identifier for ADB connection to device.
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020065 :param raise_on_error bool:
66 Whether to raise a DeviceCommandError exception if the return code is
67 less than 0.
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010068 :returns subprocess.CompletedProcess:
69 Completed process.
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020070 :raises DeviceCommandError:
71 If the command failed.
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010072 """
73
74 # Make sure the adb server is started to avoid the infamous "out of date"
75 # message that pollutes stdout.
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020076 ret = subprocess.run(
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010077 ["adb", "start-server"],
78 stdout=subprocess.PIPE,
79 stderr=subprocess.PIPE,
80 universal_newlines=True,
81 )
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020082 if ret.returncode < 0:
83 if raise_on_error:
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010084 raise DeviceCommandError(serial if serial else "??", str(args), ret.stderr)
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020085 else:
86 return None
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010087
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010088 command = ["adb"]
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010089 if serial:
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010090 command += ["-s", serial]
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010091 if args:
92 command += list(args)
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020093 ret = subprocess.run(
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010094 command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True
95 )
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010096
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +020097 if raise_on_error and ret.returncode < 0:
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +010098 raise DeviceCommandError(serial if serial else "??", str(args), ret.stderr)
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010099
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200100 return ret
101
102
Franz-Xaver Geigerb0f55422018-04-17 10:33:37 +0200103def list_devices():
104 """List serial numbers of devices attached to adb.
105
106 Raises:
107 DeviceCommandError: If the underlying adb command failed.
108 """
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100109 process = adb("devices")
Franz-Xaver Geigerb0f55422018-04-17 10:33:37 +0200110 return ADB_DEVICES_PATTERN.findall(process.stdout)
111
112
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100113def aapt(*args, raise_on_error=True):
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100114 """Run an AAPT command.
115
116 :param *args:
117 The AAPT command with its options.
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200118 :param raise_on_error bool:
119 Whether to raise a DeviceCommandError exception if the return code is
120 less than 0.
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100121 :returns subprocess.CompletedProcess:
122 Completed process.
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200123 :raises HostCommandError:
124 If the command failed.
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100125 """
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100126 command = ["aapt"]
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100127 if args:
128 command += list(args)
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200129 ret = subprocess.run(
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100130 command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True
131 )
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100132
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200133 if raise_on_error and ret.returncode < 0:
134 raise HostCommandError(str(args), ret.stderr)
135
136 return ret
137
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100138
Borjan Tchakaloff64ec42b2018-02-07 11:33:15 -0800139def force_awake(serial, always=True):
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200140 """Force the device to stay awake.
141
142 Raises:
143 DeviceCommandError: If the underlying adb command failed.
144 """
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100145 adb(
146 "shell",
147 "svc power stayon {}".format("true" if always else "false"),
148 serial=serial,
149 )
Borjan Tchakaloff64ec42b2018-02-07 11:33:15 -0800150
151
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200152def unlock(dut):
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200153 """Wake-up the device and unlock it.
154
155 Raises:
156 DeviceCommandError: If the underlying adb commands failed.
157 """
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100158 if not dut.info["screenOn"]:
159 adb("shell", "input keyevent KEYCODE_POWER", serial=dut.serial)
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200160 time.sleep(1)
161 # The KEYCODE_MENU input is enough to unlock a "swipe up to unlock"
162 # lockscreen on Android 6, but unfortunately not Android 7. So we use a
163 # swipe up (that depends on the screen resolution) instead.
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100164 adb("shell", "input touchscreen swipe 930 880 930 380", serial=dut.serial)
Borjan Tchakaloff64ec42b2018-02-07 11:33:15 -0800165 time.sleep(1)
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100166 adb("shell", "input keyevent KEYCODE_HOME", serial=dut.serial)
Borjan Tchakaloff64ec42b2018-02-07 11:33:15 -0800167
168
Franz-Xaver Geigerb3f7c982018-04-12 09:29:32 +0200169def getprop(serial, key):
170 """Get system property of device.
171
172 Example:
173 >>> getprop('167eb6e8', 'ro.build.id')
174 'FP2-gms-18.02.0'
175
176 :param str serial:
177 Identifier for ADB connection to device.
178 :param str key:
179 Key of property to get.
180 :returns str:
181 Value of system property.
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200182 :raise DeviceCommandError: If the underlying adb command failed.
Franz-Xaver Geigerb3f7c982018-04-12 09:29:32 +0200183 """
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100184 process = adb("shell", "getprop", key, serial=serial)
Franz-Xaver Geigerb3f7c982018-04-12 09:29:32 +0200185 return process.stdout.strip()
186
187
188def is_gms_device(serial):
189 """Test if device runs GMS or sibon.
190
191 Example:
192 >>> is_gms_device('167eb6e8')
193 True
194
195 :param str serial:
196 Identifier for ADB connection to device.
197 :returns bool:
198 True if device runs GMS, false otherwise.
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200199 :raise DeviceCommandError: If the underlying adb command failed.
Franz-Xaver Geigerb3f7c982018-04-12 09:29:32 +0200200 """
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100201 return getprop(serial, "ro.build.id").startswith("FP2-gms-") or getprop(
202 serial, "ro.build.version.incremental"
203 ).startswith("gms-")
Franz-Xaver Geigerb3f7c982018-04-12 09:29:32 +0200204
205
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100206def uninstall_apk(serial, filename, prebuilts_dir):
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200207 """Uninstall apk from prebuilts_dir on device.
208
209 Raises:
210 ValueError: If the package name could not be read from the apk.
211 DeviceCommandError: If the uninstall command failed.
212 """
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100213 ret = aapt("dump", "badging", "{}/{}".format(prebuilts_dir, filename))
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200214 package = None
215 for line in ret.stdout.splitlines():
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100216 if line.startswith("package"):
217 for token in line.split(" "):
218 if token.startswith("name="):
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200219 # Extract the package name out of the token
220 # (name='some.package.name')
221 package = token[6:-1]
222 break
223 if not package:
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100224 raise ValueError("Could not find package of app `{}`".format(filename))
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200225
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100226 adb("uninstall", package, serial=serial)
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100227
228
Borjan Tchakaloffd2c92ce2018-08-24 17:13:57 +0200229def install_apk(dut, filename, prebuilts_dir):
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200230 """Install apk from prebuilts_dir on device.
231
232 Raises:
233 DeviceCommandError: If the install command failed.
234 """
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100235 path = os.path.join(prebuilts_dir, filename)
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100236 command = ["install", "-r"]
Borjan Tchakaloffd2c92ce2018-08-24 17:13:57 +0200237 if dut.sdk >= 23:
238 # From Marshmallow onwards, adb has a flag to grant default permissions
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100239 command.append("-g")
Borjan Tchakaloffd2c92ce2018-08-24 17:13:57 +0200240 adb(*command, path, serial=dut.serial)
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100241
242
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200243def configure_wifi_networks(dut, networks):
244 """Configure Wi-Fi networks.
245
246 The `networks` parameters is a list of networks to configure hashed by
247 their SSID. Each network value should have the following format:
248 - security (str): The security value as can be found in the Wi-Fi
249 settings dialog. Common values are 'None' and 'WPA/WPA2 PSK'.
250 - password (str, optional): The network password if the security is
251 'WPA/WPA2 PSK'.
252
253 Parameters:
254 dut (Device): The device object.
255 networks (dict(dict(str))): The list of networks to configure.
256 Raises:
257 DeviceCommandError: If the UI automation fails.
258 """
259 # Open the Wi-Fi settings
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100260 adb(
261 "shell",
262 "am start -a android.settings.WIFI_SETTINGS --activity-clear-task",
263 serial=dut.serial,
264 )
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200265
266 # Make sure Wi-Fi is enabled
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100267 wifi_enabler = dut(text="OFF", resourceId="com.android.settings:id/switch_widget")
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200268 if wifi_enabler.exists:
269 wifi_enabler.click()
270
271 # Check for registered networks
272 registered_networks = set()
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100273 dut(description="More options").click.wait()
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200274 time.sleep(1)
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100275 saved_networks = dut(text="Saved networks")
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200276 if saved_networks.exists:
Borjan Tchakaloff1d83e562018-05-16 18:47:04 +0200277 saved_networks.click.wait()
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200278 for ssid in networks.keys():
279 if dut(text=ssid).exists:
280 registered_networks.add(ssid)
281 dut.press.back()
282
283 missing_networks = networks.keys() - registered_networks
284
285 for ssid in registered_networks:
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100286 print("Ignoring `{}` Wi-Fi network, already configured.".format(ssid))
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200287
288 for ssid in missing_networks:
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100289 print("Configuring `{}` Wi-Fi network…".format(ssid))
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200290
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100291 dut(description="More options").click.wait()
292 dut(text="Add network").click.wait()
293 dut(resourceId="com.android.settings:id/ssid").set_text(ssid)
294 dut(resourceId="com.android.settings:id/security").click()
295 dut(text=networks[ssid]["security"]).click()
296 password_field = dut(resourceId="com.android.settings:id/password")
Karsten Tauschec20f4f32019-03-04 14:32:04 +0100297 time.sleep(1)
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100298 if "password" in networks[ssid] and networks[ssid]["password"]:
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200299 if not password_field.exists:
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100300 dut(text="Cancel").click()
301 raise DeviceCommandError(dut, "UI: add Wi-Fi", "missing password field")
302 password_field.set_text(networks[ssid]["password"])
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200303 elif password_field.exists:
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100304 dut(text="Cancel").click()
305 raise DeviceCommandError(dut, "UI: add Wi-Fi", "missing password data")
306 save_button = dut(text="Save")
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200307 if not save_button.click():
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100308 dut(text="Cancel").click()
309 raise DeviceCommandError(dut, "UI: add Wi-Fi", "could not save network")
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200310
311 # Force the Wi-Fi on and off to pick the best network available
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100312 dut(text="ON", resourceId="com.android.settings:id/switch_widget").click()
313 dut(text="OFF", resourceId="com.android.settings:id/switch_widget").click()
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200314
315 # Leave the settings
316 dut.press.back()
317
318
Karsten Tauscheb36529f2019-03-02 14:13:29 +0100319def disable_privacy_impact_popup(dut):
320 """Disable Privacy Impact popup on Android 5.
321
322 This simplifies UI automation. Disabling the feature globally is more robust
323 than clicking through the the Privacy Impact screen per app.
324 """
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100325 print("Disabling the Privacy Impact screen…")
326 adb(
327 "shell",
328 (
329 "am start -a android.intent.action.MAIN "
330 "com.fairphone.privacyimpact/.PrivacyImpactPreferenceActivity"
331 ),
332 serial=dut.serial,
Karsten Tauscheb36529f2019-03-02 14:13:29 +0100333 )
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100334 disable_privacy_impact_checkbox = dut(className="android.widget.CheckBox")
Karsten Tauscheb36529f2019-03-02 14:13:29 +0100335 if not disable_privacy_impact_checkbox.checked:
336 disable_privacy_impact_checkbox.click()
337
338
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200339def get_proxy_apk(android_sdk, flavour):
340 if android_sdk >= 24:
341 return PREBUILT_PROXY_APK_PATTERN.format(sdk=24, flavour=flavour)
342 else:
343 return PREBUILT_PROXY_APK_PATTERN.format(sdk=19, flavour=flavour)
344
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100345
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100346# Prepare the DUT
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200347def prepare_dut(dut, scenarios_dir, data_dir, prebuilts_dir):
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100348 flavour = "gms" if is_gms_device(dut.serial) else "sibon"
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200349 proxy_apk = get_proxy_apk(dut.sdk, flavour)
Franz-Xaver Geigerb3f7c982018-04-12 09:29:32 +0200350
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100351 # Uninstall the smartviser apps
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200352 for app in PREBUILT_APKS + [proxy_apk]:
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100353 print("Uninstalling `{}`…".format(app))
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200354 uninstall_apk(dut.serial, app, prebuilts_dir)
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100355
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100356 # Copy the scenarios
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100357 print("Pushing scenarios from `{}`…".format(scenarios_dir))
358 adb("push", scenarios_dir, "/sdcard/viser", serial=dut.serial)
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100359
360 # Copy the scenarios data
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100361 print("Pushing scenarios data from `{}`…".format(data_dir))
362 adb("push", data_dir, "/sdcard/viser/data", serial=dut.serial)
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100363
Franz-Xaver Geigerb3f7c982018-04-12 09:29:32 +0200364 # Install the smartviser apps (starting with the proxy app)
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200365 for app in [proxy_apk] + PREBUILT_APKS:
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100366 print("Installing `{}`…".format(app))
Borjan Tchakaloffd2c92ce2018-08-24 17:13:57 +0200367 install_apk(dut, app, prebuilts_dir)
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100368
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100369
370# Grant the permissions through the UI
371def configure_perms(dut):
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100372 # Input the credentials
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100373 dut(resourceId="android:id/content").child(text="Username").child(
374 className="android.widget.EditText"
375 ).set_text(VWS_CREDENTIALS["user"])
376 dut(resourceId="android:id/content").child(text="Password").child(
377 className="android.widget.EditText"
378 ).set_text(VWS_CREDENTIALS["password"])
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100379
380 # Sign in
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100381 signin_label = "SIGN IN" if dut.sdk >= 24 else "Sign in"
382 dut(resourceId="android:id/content").child(
383 text=signin_label, className="android.widget.Button"
384 ).click()
385
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100386
387def configure_sms(dut):
388 # TODO wait for the connection to be established and time-out
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100389 prompt = dut(resourceId="android:id/content").child(
390 text="Viser must be your SMS app to send messages"
391 )
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100392 while not prompt.exists:
393 time.sleep(1)
394
395 # Make viser the default SMS app
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100396 dut(resourceId="android:id/content").child_by_text(
397 "Viser must be your SMS app to send messages",
398 className="android.widget.LinearLayout",
399 ).child(text="OK", className="android.widget.Button").click()
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100400
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100401 dut(resourceId="android:id/content").child_by_text(
402 "Change SMS app?", className="android.widget.LinearLayout"
403 ).child(text="Yes", className="android.widget.Button").click()
404
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100405
406def configure_settings(dut):
407 # Set the e-mail account
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100408 dut(text="Settings", className="android.widget.TextView").click()
409 dut(resourceId="android:id/list").child_by_text(
410 "User settings", className="android.widget.LinearLayout"
411 ).click()
412 dut(resourceId="android:id/list").child_by_text(
413 "Email account", className="android.widget.LinearLayout"
414 ).click()
415 prompt = dut(resourceId="android:id/content").child_by_text(
416 "Email account", className="android.widget.LinearLayout"
417 )
418 prompt.child(resourceId="android:id/edit").set_text("fairphone.viser@gmail.com")
419 prompt.child(text="OK", className="android.widget.Button").click()
420 dut(resourceId="android:id/list").child_by_text(
421 "Email password", className="android.widget.LinearLayout"
422 ).click()
423 dut(text="Password :").child(className="android.widget.EditText").set_text(
424 "fairphoneviser2017"
425 )
426 dut(description="OK", className="android.widget.TextView").click()
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100427 dut.press.back()
428 dut.press.back()
429
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100430
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100431def deploy():
432 serials = []
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100433
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100434 if len(sys.argv) > 1:
435 serials.append(sys.argv[1])
436 else:
Franz-Xaver Geigerb0f55422018-04-17 10:33:37 +0200437 serials = list_devices()
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100438
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100439 for serial in serials:
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100440 print("Configuring device {}…".format(serial))
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100441
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100442 dut = Device(serial)
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200443 # Work around the not-so-easy Device class
444 dut.serial = serial
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200445 # Cache the Android SDK version (dut.info fetches system properties)
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100446 dut.sdk = dut.info["sdkInt"]
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100447
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200448 try:
449 # Make sure the screen stays on - we're going to use UI automation
450 force_awake(serial)
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200451 unlock(dut)
Borjan Tchakaloff64ec42b2018-02-07 11:33:15 -0800452
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200453 # Configure common Fairphone Wi-Fi networks
Borjan Tchakaloffd4ce8072018-05-16 18:20:13 +0200454 if dut.sdk < 24:
455 configure_wifi_networks(dut, FAIRPHONE_WIFI_NETWORKS)
456 else:
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100457 print(
458 "Uh oh, the device is running Android SDK {} on which we "
459 "do not deploy Wi-Fi networks yet.".format(dut.sdk)
460 )
Borjan Tchakaloff74d962a2018-04-11 17:47:14 +0200461
Karsten Tauscheb36529f2019-03-02 14:13:29 +0100462 # Disable Privacy Impact popup on Android 5.
463 if dut.sdk <= 22:
464 disable_privacy_impact_popup(dut)
465
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200466 # Push the scenarios, their data, and install the apps
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100467 prepare_dut(dut, "../scenarios", "../scenarios-data", PREBUILTS_PATH)
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100468
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200469 # Start the viser app
470 adb(
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100471 "shell",
472 "monkey",
473 "-p",
474 "com.lunarlabs.panda",
475 "-c",
476 "android.intent.category.LAUNCHER",
477 "1",
478 serial=serial,
479 )
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:
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100489 print("ERROR {}".format(e), file=sys.stderr)
Borjan Tchakaloffde9fa0f2018-04-12 12:05:48 +0200490 finally:
491 try:
492 # Leave the device alone now
493 force_awake(serial, always=False)
494 except DeviceCommandError as e:
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100495 print("WARNING {}".format(e), file=sys.stderr)
Borjan Tchakaloff64ec42b2018-02-07 11:33:15 -0800496
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100497
Borjan Tchakaloff7d4f6152020-01-24 15:41:00 +0100498if __name__ == "__main__":
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100499 deploy()