blob: 7a8b5d99afd18195c7093722dcd88f9b3ff355ed [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
6import sys
7import subprocess
8import pathlib
9
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010010
11PREBUILTS_PATH = '../../vendor/smartviser/viser/prebuilts/apk'
12
Franz-Xaver Geigerb3f7c982018-04-12 09:29:32 +020013PREBUILT_PROXY_APKS = {
14 'gms': 'com.lunarlabs.panda.proxy.apk',
15 'sibon': 'com.lunarlabs.panda.proxy-sibon.apk',
16}
17
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010018PREBUILT_APKS = [
19 'com.smartviser.demogame.apk',
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +010020 'com.lunarlabs.panda.apk',
21]
22
23
24def adb(*args, serial = None):
25 """Run ADB command attached to serial.
26
27 Example:
28 >>> process = adb('shell', 'getprop', 'ro.build.fingerprint', serial='cc60c021')
29 >>> process.returncode
30 0
31 >>> process.stdout.strip()
32 'Fairphone/FP2/FP2:6.0.1/FP2-gms-18.02.0/FP2-gms-18.02.0:user/release-keys'
33
34 :param *args:
35 List of options to ADB (including command).
36 :param str serial:
37 Identifier for ADB connection to device.
38 :returns subprocess.CompletedProcess:
39 Completed process.
40 """
41
42 # Make sure the adb server is started to avoid the infamous "out of date"
43 # message that pollutes stdout.
44 subprocess.run(
45 ['adb', 'start-server'], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
46 universal_newlines=True)
47
48 command = ['adb']
49 if serial:
50 command += ['-s', serial]
51 if args:
52 command += list(args)
53 return subprocess.run(
54 command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
55 universal_newlines=True)
56
57
58def aapt(*args):
59 """Run an AAPT command.
60
61 :param *args:
62 The AAPT command with its options.
63 :returns subprocess.CompletedProcess:
64 Completed process.
65 """
66 command = ['aapt']
67 if args:
68 command += list(args)
69 return subprocess.run(
70 command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
71 universal_newlines=True)
72
73
Franz-Xaver Geigerb3f7c982018-04-12 09:29:32 +020074def getprop(serial, key):
75 """Get system property of device.
76
77 Example:
78 >>> getprop('167eb6e8', 'ro.build.id')
79 'FP2-gms-18.02.0'
80
81 :param str serial:
82 Identifier for ADB connection to device.
83 :param str key:
84 Key of property to get.
85 :returns str:
86 Value of system property.
87 """
88 process = adb('shell', 'getprop', key, serial=serial)
89 return process.stdout.strip()
90
91
92def is_gms_device(serial):
93 """Test if device runs GMS or sibon.
94
95 Example:
96 >>> is_gms_device('167eb6e8')
97 True
98
99 :param str serial:
100 Identifier for ADB connection to device.
101 :returns bool:
102 True if device runs GMS, false otherwise.
103 """
104 return getprop(serial, 'ro.build.id').startswith('FP2-gms-')
105
106
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100107def uninstall_apk(serial, filename, prebuilts_dir):
108 """Uninstall apk from prebuilts_dir on device."""
109 ret = aapt('dump', 'badging', '{}/{}'.format(prebuilts_dir, filename))
110 if 0 < ret.returncode:
111 print('Could retrieve app `{}` info, error was: {}'.format(
112 filename, ret.stderr), file=sys.stderr)
113 else:
114 package = None
115 for line in ret.stdout.splitlines():
116 if line.startswith('package'):
117 for token in line.split(' '):
118 if token.startswith('name='):
119 # Extract the package name out of the token
120 # (name='some.package.name')
121 package = token[6:-1]
122 break
123 if not package:
124 print('Could not find package of app `{}`'.format(filename),
125 file=sys.stderr)
126 else:
127 print('Uninstalling `{}`'.format(package))
128 ret = adb('uninstall', package, serial=serial)
129 if 0 < ret.returncode:
130 print('Could not uninstall app `{}`, error was: {}'.format(
131 filename, ret.stderr), file=sys.stderr)
132 else:
133 print('App `{}` uninstalled.'.format(filename))
134
135
136def install_apk(serial, filename, prebuilts_dir):
137 """Install apk from prebuilts_dir on device."""
138 print('Installing {}.'.format(filename))
139 path = os.path.join(prebuilts_dir, filename)
140 ret = adb('install', '-r', path, serial=serial)
141 if 0 < ret.returncode:
142 print('Could not install app `{}`, error was: {}'.format(
143 filename, ret.stderr), file=sys.stderr)
144 else:
145 print('App `{}` installed.'.format(filename))
146
147
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100148# Prepare the DUT
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100149def prepare_dut(serial, scenarios_dir, data_dir, prebuilts_dir):
Franz-Xaver Geigerb3f7c982018-04-12 09:29:32 +0200150 flavour = 'gms' if is_gms_device(serial) else 'sibon'
151
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100152 # Uninstall the smartviser apps
Franz-Xaver Geigerb3f7c982018-04-12 09:29:32 +0200153 for app in PREBUILT_APKS + [PREBUILT_PROXY_APKS[flavour]]:
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100154 uninstall_apk(serial, app, prebuilts_dir)
155
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100156 # Copy the scenarios
Franz-Xaver Geiger223ae752018-02-19 14:54:08 +0100157 ret = adb('push', scenarios_dir, '/sdcard/viser', serial=serial)
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100158 if 0 < ret.returncode:
159 print('Could not push the scenarios, error was: {}'.format(ret.stderr),
160 file=sys.stderr)
161 else:
162 print('Scenarios pushed.')
163
164 # Copy the scenarios data
Franz-Xaver Geiger223ae752018-02-19 14:54:08 +0100165 ret = adb('push', data_dir, '/sdcard/viser/data', serial=serial)
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100166 if 0 < ret.returncode:
167 print('Could not push the scenarios data, error was: {}'.format(ret.stderr),
168 file=sys.stderr)
169 else:
170 print('Scenarios data pushed.')
171
Franz-Xaver Geigerb3f7c982018-04-12 09:29:32 +0200172 # Install the smartviser apps (starting with the proxy app)
173 for app in [PREBUILT_PROXY_APKS[flavour]] + PREBUILT_APKS:
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100174 install_apk(serial, app, prebuilts_dir)
175
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100176
177# Grant the permissions through the UI
178def configure_perms(dut):
Borjan Tchakaloff6dad85d2018-04-11 13:55:25 +0200179 dut() \
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100180 .child_by_text('You need to grant access for the Permissions Group '
181 'Calendar Camera Contacts Microphone SMS Storage Telephone Location',
Borjan Tchakaloff6dad85d2018-04-11 13:55:25 +0200182 resourceId='android:id/content') \
183 .child(text='OK', className='android.widget.Button') \
184 .click()
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100185
186 # Accept any permission that is asked for
187 prompt = dut(resourceId='com.android.packageinstaller:id/permission_allow_button',
188 className='android.widget.Button')
189 while prompt.exists:
190 prompt.click()
191
192 # Input the credentials
193 dut(resourceId='android:id/content') \
194 .child(text='Username') \
195 .child(className='android.widget.EditText') \
196 .set_text('borjan@fairphone.com')
197 dut(resourceId='android:id/content') \
198 .child(text='Password') \
199 .child(className='android.widget.EditText') \
200 .set_text('Rickisalso1niceguy!')
201
202 # Sign in
203 dut(resourceId='android:id/content') \
204 .child(text='Sign in', className='android.widget.Button') \
205 .click()
206
207def configure_sms(dut):
208 # TODO wait for the connection to be established and time-out
209 prompt = dut(resourceId='android:id/content') \
210 .child(text='Viser must be your SMS app to send messages')
211 while not prompt.exists:
212 time.sleep(1)
213
214 # Make viser the default SMS app
215 dut(resourceId='android:id/content') \
216 .child_by_text('Viser must be your SMS app to send messages',
217 className='android.widget.LinearLayout') \
218 .child(text='OK', className='android.widget.Button') \
219 .click()
220
221 dut(resourceId='android:id/content') \
222 .child_by_text('Change SMS app?', className='android.widget.LinearLayout') \
223 .child(text='Yes', className='android.widget.Button') \
224 .click()
225
226def configure_settings(dut):
227 # Set the e-mail account
228 dut(text='Settings', className='android.widget.TextView') \
229 .click()
230 dut(resourceId='android:id/list') \
231 .child_by_text('User settings', className='android.widget.LinearLayout') \
232 .click()
233 dut(resourceId='android:id/list') \
234 .child_by_text('Email account', className='android.widget.LinearLayout') \
235 .click()
236 prompt = dut(resourceId='android:id/content') \
237 .child_by_text('Email account', className='android.widget.LinearLayout')
238 prompt.child(resourceId='android:id/edit') \
239 .set_text('fairphone.viser@gmail.com')
240 prompt.child(text='OK', className='android.widget.Button') \
241 .click()
242 dut(resourceId='android:id/list') \
243 .child_by_text('Email password', className='android.widget.LinearLayout') \
244 .click()
245 dut(text='Password :') \
246 .child(className='android.widget.EditText') \
247 .set_text('fairphoneviser2017')
248 dut(description='OK', className='android.widget.TextView') \
249 .click()
250 dut.press.back()
251 dut.press.back()
252
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100253
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100254def deploy():
255 serials = []
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100256
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100257 if len(sys.argv) > 1:
258 serials.append(sys.argv[1])
259 else:
260 # List devices attached to adb
261 ret = subprocess.run(
262 "adb devices | grep -E '^[a-z0-9-]+\s+device$' | awk '{{print $1}}'",
263 shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
264 universal_newlines=True)
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100265
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100266 if 0 < ret.returncode:
267 # TODO handle the error
268 raise Exception('Failed to list adb devices')
269 elif ret.stdout:
270 for line in ret.stdout.splitlines():
271 serial = line.strip()
272 if serial:
273 serials.append(serial)
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100274
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100275 for serial in serials:
276 print('Configuring device {}'.format(serial))
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100277
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100278 dut = Device(serial)
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100279
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100280 # Push the scenarios, their data, and install the apps
Franz-Xaver Geigerb28348e2018-02-19 14:41:40 +0100281 prepare_dut(serial, '../scenarios', '../scenarios-data', PREBUILTS_PATH)
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100282
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100283 # Start the viser app
Franz-Xaver Geiger223ae752018-02-19 14:54:08 +0100284 ret = adb(
285 'shell', 'monkey', '-p', 'com.lunarlabs.panda', '-c',
286 'android.intent.category.LAUNCHER', '1', serial=serial)
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100287 if 0 < ret.returncode:
288 print('Could not start the viser app, error was: {}'.format(app,
289 ret.stderr), file=sys.stderr)
290 exit(-1)
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100291
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100292 configure_perms(dut)
Borjan Tchakaloffa4bdae12017-11-21 14:58:12 +0100293
Franz-Xaver Geigerd1079e22018-02-19 14:34:15 +0100294 # TODO DO NOT DO THE FOLLOWING IF NO SIM CARD IS IN THE DUT
295 # time.sleep(10)
296 # configure_sms(dut)
297
298 configure_settings(dut)
299
300
301if __name__ == '__main__':
302 deploy()