blob: 9e7976a9b7b04cf56c8c2be73250eea0de6dc093 [file] [log] [blame]
#!/usr/bin/env python3
import os
import time
from uiautomator import Device
import sys
import subprocess
import pathlib
PREBUILTS_PATH = '../../vendor/smartviser/viser/prebuilts/apk'
PREBUILT_PROXY_APKS = {
'gms': 'com.lunarlabs.panda.proxy.apk',
'sibon': 'com.lunarlabs.panda.proxy-sibon.apk',
}
PREBUILT_APKS = [
'com.smartviser.demogame.apk',
'com.lunarlabs.panda.apk',
]
def adb(*args, serial = None):
"""Run ADB command attached to serial.
Example:
>>> process = adb('shell', 'getprop', 'ro.build.fingerprint', serial='cc60c021')
>>> process.returncode
0
>>> process.stdout.strip()
'Fairphone/FP2/FP2:6.0.1/FP2-gms-18.02.0/FP2-gms-18.02.0:user/release-keys'
:param *args:
List of options to ADB (including command).
:param str serial:
Identifier for ADB connection to device.
:returns subprocess.CompletedProcess:
Completed process.
"""
# Make sure the adb server is started to avoid the infamous "out of date"
# message that pollutes stdout.
subprocess.run(
['adb', 'start-server'], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True)
command = ['adb']
if serial:
command += ['-s', serial]
if args:
command += list(args)
return subprocess.run(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True)
def aapt(*args):
"""Run an AAPT command.
:param *args:
The AAPT command with its options.
:returns subprocess.CompletedProcess:
Completed process.
"""
command = ['aapt']
if args:
command += list(args)
return subprocess.run(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True)
def force_awake(serial, always=True):
"""Force the device to stay awake."""
return adb('shell', 'svc power stayon {}'.format(
'true' if always else 'false'), serial=serial)
def unlock(serial):
"""Wake-up the device and unlock it."""
adb('shell', 'input keyevent KEYCODE_POWER', serial=serial)
time.sleep(1)
adb('shell', 'input keyevent KEYCODE_MENU', serial=serial)
time.sleep(1)
adb('shell', 'input keyevent KEYCODE_HOME', serial=serial)
def getprop(serial, key):
"""Get system property of device.
Example:
>>> getprop('167eb6e8', 'ro.build.id')
'FP2-gms-18.02.0'
:param str serial:
Identifier for ADB connection to device.
:param str key:
Key of property to get.
:returns str:
Value of system property.
"""
process = adb('shell', 'getprop', key, serial=serial)
return process.stdout.strip()
def is_gms_device(serial):
"""Test if device runs GMS or sibon.
Example:
>>> is_gms_device('167eb6e8')
True
:param str serial:
Identifier for ADB connection to device.
:returns bool:
True if device runs GMS, false otherwise.
"""
return getprop(serial, 'ro.build.id').startswith('FP2-gms-')
def uninstall_apk(serial, filename, prebuilts_dir):
"""Uninstall apk from prebuilts_dir on device."""
ret = aapt('dump', 'badging', '{}/{}'.format(prebuilts_dir, filename))
if 0 < ret.returncode:
print('Could retrieve app `{}` info, error was: {}'.format(
filename, ret.stderr), file=sys.stderr)
else:
package = None
for line in ret.stdout.splitlines():
if line.startswith('package'):
for token in line.split(' '):
if token.startswith('name='):
# Extract the package name out of the token
# (name='some.package.name')
package = token[6:-1]
break
if not package:
print('Could not find package of app `{}`'.format(filename),
file=sys.stderr)
else:
print('Uninstalling `{}`'.format(package))
ret = adb('uninstall', package, serial=serial)
if 0 < ret.returncode:
print('Could not uninstall app `{}`, error was: {}'.format(
filename, ret.stderr), file=sys.stderr)
else:
print('App `{}` uninstalled.'.format(filename))
def install_apk(serial, filename, prebuilts_dir):
"""Install apk from prebuilts_dir on device."""
print('Installing {}.'.format(filename))
path = os.path.join(prebuilts_dir, filename)
ret = adb('install', '-r', path, serial=serial)
if 0 < ret.returncode:
print('Could not install app `{}`, error was: {}'.format(
filename, ret.stderr), file=sys.stderr)
else:
print('App `{}` installed.'.format(filename))
# Prepare the DUT
def prepare_dut(serial, scenarios_dir, data_dir, prebuilts_dir):
flavour = 'gms' if is_gms_device(serial) else 'sibon'
# Uninstall the smartviser apps
for app in PREBUILT_APKS + [PREBUILT_PROXY_APKS[flavour]]:
uninstall_apk(serial, app, prebuilts_dir)
# Copy the scenarios
ret = adb('push', scenarios_dir, '/sdcard/viser', serial=serial)
if 0 < ret.returncode:
print('Could not push the scenarios, error was: {}'.format(ret.stderr),
file=sys.stderr)
else:
print('Scenarios pushed.')
# Copy the scenarios data
ret = adb('push', data_dir, '/sdcard/viser/data', serial=serial)
if 0 < ret.returncode:
print('Could not push the scenarios data, error was: {}'.format(ret.stderr),
file=sys.stderr)
else:
print('Scenarios data pushed.')
# Install the smartviser apps (starting with the proxy app)
for app in [PREBUILT_PROXY_APKS[flavour]] + PREBUILT_APKS:
install_apk(serial, app, prebuilts_dir)
# Grant the permissions through the UI
def configure_perms(dut):
dut() \
.child_by_text('You need to grant access for the Permissions Group '
'Calendar Camera Contacts Microphone SMS Storage Telephone Location',
resourceId='android:id/content') \
.child(text='OK', className='android.widget.Button') \
.click()
# Accept any permission that is asked for
prompt = dut(resourceId='com.android.packageinstaller:id/permission_allow_button',
className='android.widget.Button')
while prompt.exists:
prompt.click()
# Input the credentials
dut(resourceId='android:id/content') \
.child(text='Username') \
.child(className='android.widget.EditText') \
.set_text('borjan@fairphone.com')
dut(resourceId='android:id/content') \
.child(text='Password') \
.child(className='android.widget.EditText') \
.set_text('Rickisalso1niceguy!')
# Sign in
dut(resourceId='android:id/content') \
.child(text='Sign in', className='android.widget.Button') \
.click()
def configure_sms(dut):
# TODO wait for the connection to be established and time-out
prompt = dut(resourceId='android:id/content') \
.child(text='Viser must be your SMS app to send messages')
while not prompt.exists:
time.sleep(1)
# Make viser the default SMS app
dut(resourceId='android:id/content') \
.child_by_text('Viser must be your SMS app to send messages',
className='android.widget.LinearLayout') \
.child(text='OK', className='android.widget.Button') \
.click()
dut(resourceId='android:id/content') \
.child_by_text('Change SMS app?', className='android.widget.LinearLayout') \
.child(text='Yes', className='android.widget.Button') \
.click()
def configure_settings(dut):
# Set the e-mail account
dut(text='Settings', className='android.widget.TextView') \
.click()
dut(resourceId='android:id/list') \
.child_by_text('User settings', className='android.widget.LinearLayout') \
.click()
dut(resourceId='android:id/list') \
.child_by_text('Email account', className='android.widget.LinearLayout') \
.click()
prompt = dut(resourceId='android:id/content') \
.child_by_text('Email account', className='android.widget.LinearLayout')
prompt.child(resourceId='android:id/edit') \
.set_text('fairphone.viser@gmail.com')
prompt.child(text='OK', className='android.widget.Button') \
.click()
dut(resourceId='android:id/list') \
.child_by_text('Email password', className='android.widget.LinearLayout') \
.click()
dut(text='Password :') \
.child(className='android.widget.EditText') \
.set_text('fairphoneviser2017')
dut(description='OK', className='android.widget.TextView') \
.click()
dut.press.back()
dut.press.back()
def deploy():
serials = []
if len(sys.argv) > 1:
serials.append(sys.argv[1])
else:
# List devices attached to adb
ret = subprocess.run(
"adb devices | grep -E '^[a-z0-9-]+\s+device$' | awk '{{print $1}}'",
shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True)
if 0 < ret.returncode:
# TODO handle the error
raise Exception('Failed to list adb devices')
elif ret.stdout:
for line in ret.stdout.splitlines():
serial = line.strip()
if serial:
serials.append(serial)
for serial in serials:
print('Configuring device {}'.format(serial))
dut = Device(serial)
# Make sure the screen stays on - we're going to use UI automation
force_awake(serial)
unlock(serial)
# Push the scenarios, their data, and install the apps
prepare_dut(serial, '../scenarios', '../scenarios-data', PREBUILTS_PATH)
# Start the viser app
ret = adb(
'shell', 'monkey', '-p', 'com.lunarlabs.panda', '-c',
'android.intent.category.LAUNCHER', '1', serial=serial)
if 0 < ret.returncode:
print('Could not start the viser app, error was: {}'.format(app,
ret.stderr), file=sys.stderr)
exit(-1)
configure_perms(dut)
# TODO DO NOT DO THE FOLLOWING IF NO SIM CARD IS IN THE DUT
# time.sleep(10)
# configure_sms(dut)
configure_settings(dut)
# Leave the device alone now
force_awake(serial, always=False)
if __name__ == '__main__':
deploy()