Updates script to generate images automatically on emulator
Bug: 64529725
Test: ./cts/hostsidetests/theme/run_theme_capture_device.py Nexus_5_API_27
Change-Id: I38d731ffc899a25422842236e4f974ffc6f2e102
diff --git a/hostsidetests/theme/README b/hostsidetests/theme/README
index 64ca416..4f93e5a 100644
--- a/hostsidetests/theme/README
+++ b/hostsidetests/theme/README
@@ -30,33 +30,42 @@
I. Generating reference images (CTS maintainers only)
Reference images are typically only generated for new API revisions. To
-generate a new set of reference images, do the following:
+generate a new set of reference images from an emulator, do the following:
- 1. Obtain the emulator image for the current platform. You can either build
- these from scratch (not recommended) via:
+ 1. Ensure the Android SDK is installed locally. Either a public or internal
+ distribution is fine. From the console, set the ANDROID_SDK_ROOT env var:
- make PRODUCT-sdk_phone_x86_64-sdk sdk_repo -j32
+ export ANDROID_SDK_ROOT = /path/to/sdk
- Or obtain them from the sdk-repo-linux-system-images-<build-id>.zip
- artifact from the sdk_phone_x86_64-sdk build server target.
+ 2. Obtain an x86_64 emulator image from the build server by using the script
+ available internally at go/emu-dev. This script will install the image in
+ your SDK.
- 2. Start one AVD emulator image for each DPI bucket (ldpi, xxxhdpi, etc.)
- that you wish to generate references images for. Anecdotally, up to three
- emulators can run reliably at the same time. Confirm that all emulators
- are connected with:
+ 3. Use the SDK's AVD Manager tool to create a single virtual device using the
+ emulator image from step 2. The exact configuration doesn't really matter;
+ you can use Nexus 5 as a template. Name the emulator "theme_emulator".
- adb devices
-
- 3. Set up your build environment for x86_64 and build CTS:
+ 4. From the console, set up your build environment for x86_64 and build CTS:
lunch sdk_x86_64-eng && make cts -j32
- 2. Generate the reference images. Generation occurs on all devices in
- parallel. Resulting sets of reference images are automatically saved in
- assets/<platform>/<dpi>.zip and will overwrite any existing sets. Image
- generation may be started using:
+ 5. Use the reference image script to generate the reference images. The script
+ will automatically start the emulator in the required configurations and
+ install the resulting reference images in assets/<platform>/<dpi>.zip,
+ overwriting any existing images.
- ./cts/hostsidetests/theme/generate_images.sh
+ ./cts/hostsidetests/theme/generate_images.py theme_emulator
+
+You can also generate reference images using a real device. To generate a new set
+of reference images from a real device, do the following:
+
+ 1. Connect the device. Verify the device is connected:
+
+ adb devices
+
+ 2. Use the reference image script to generate the reference images:
+
+ ./cts/hostsidetests/theme/generate_images.py
A complete collection of reference images for a given API revision must include
a set for each possible DPI bucket (tvdpi, xxhdpi, etc.) that may be tested.
diff --git a/hostsidetests/theme/android_device.py b/hostsidetests/theme/android_device.py
index 4c7d8d1..7711060 100644
--- a/hostsidetests/theme/android_device.py
+++ b/hostsidetests/theme/android_device.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python3
#
# Copyright (C) 2015 The Android Open Source Project
#
@@ -17,106 +17,119 @@
import os
import re
+import subprocess
import sys
import threading
-import subprocess
import time
+from subprocess import PIPE
+
+
# class for running android device from python
# it will fork the device processor
-class androidDevice(object):
- def __init__(self, adbDevice):
- self._adbDevice = adbDevice
+class AndroidDevice(object):
+ def __init__(self, serial):
+ self._serial = serial
- def runAdbCommand(self, cmd):
- self.waitForAdbDevice()
- adbCmd = "adb -s %s %s" %(self._adbDevice, cmd)
- print adbCmd
- adbProcess = subprocess.Popen(adbCmd.split(" "), bufsize = -1, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
- return adbProcess.communicate()
+ def run_adb_command(self, cmd, timeout=None):
+ adb_cmd = "adb -s %s %s" % (self._serial, cmd)
+ print(adb_cmd)
- def runShellCommand(self, cmd):
- return self.runAdbCommand("shell " + cmd)
+ adb_process = subprocess.Popen(args=adb_cmd.split(), bufsize=-1, stderr=PIPE, stdout=PIPE)
+ (out, err) = adb_process.communicate(timeout=timeout)
+ return out.decode('utf-8').strip(), err.decode('utf-8').strip()
- def waitForAdbDevice(self):
- print "waitForAdbDevice"
- os.system("adb -s %s wait-for-device" %self._adbDevice)
+ def run_shell_command(self, cmd):
+ return self.run_adb_command("shell %s" % cmd)
- def waitForBootComplete(self, timeout = 240):
+ def wait_for_device(self, timeout=30):
+ return self.run_adb_command('wait-for-device', timeout)
+
+ def wait_for_prop(self, key, value, timeout=30):
boot_complete = False
attempts = 0
- wait_period = 5
+ wait_period = 1
while not boot_complete and (attempts*wait_period) < timeout:
- (output, err) = self.runShellCommand("getprop dev.bootcomplete")
- output = output.strip()
- if output == "1":
+ (out, err) = self.run_shell_command("getprop %s" % key)
+ if out == value:
boot_complete = True
else:
time.sleep(wait_period)
attempts += 1
if not boot_complete:
- print "***boot not complete within timeout. will proceed to the next step"
+ print("%s not set to %s within timeout!" % (key, value))
return boot_complete
- def installApk(self, apkPath):
- (out, err) = self.runAdbCommand("install -r -d -g " + apkPath)
- result = err.split()
- return (out, err, "Success" in result)
+ def wait_for_service(self, name, timeout=30):
+ service_found = False
+ attempts = 0
+ wait_period = 1
+ while not service_found and (attempts*wait_period) < timeout:
+ (output, err) = self.run_shell_command("service check %s" % name)
+ if 'not found' not in output:
+ service_found = True
+ else:
+ time.sleep(wait_period)
+ attempts += 1
+ if not service_found:
+ print("Service '%s' not found within timeout!" % name)
+ return service_found
- def uninstallApk(self, package):
- (out, err) = self.runAdbCommand("uninstall " + package)
- result = err.split()
+ def wait_for_boot_complete(self, timeout=60):
+ return self.wait_for_prop('dev.bootcomplete', '1', timeout)
+
+ def install_apk(self, apk_path):
+ self.wait_for_service('package')
+ (out, err) = self.run_adb_command("install -r -d -g %s" % apk_path)
+ result = out.split()
+ return out, err, "Success" in result
+
+ def uninstall_package(self, package):
+ self.wait_for_service('package')
+ (out, err) = self.run_adb_command("uninstall %s" % package)
+ result = out.split()
return "Success" in result
- def runInstrumentationTest(self, option):
- return self.runShellCommand("am instrument -w --no-window-animation " + option)
+ def run_instrumentation_test(self, option):
+ self.wait_for_service('activity')
+ return self.run_shell_command("am instrument -w --no-window-animation %s" % option)
- def isProcessAlive(self, processName):
- (out, err) = self.runShellCommand("ps")
+ def is_process_alive(self, process_name):
+ (out, err) = self.run_shell_command("ps")
names = out.split()
# very lazy implementation as it does not filter out things like uid
# should work mostly unless processName is too simple to overlap with
# uid. So only use name like com.android.xyz
- return processName in names
+ return process_name in names
- def getVersionSdkInt(self):
- return int(self.runShellCommand("getprop ro.build.version.sdk")[0])
+ def get_version_sdk(self):
+ return int(self.run_shell_command("getprop ro.build.version.sdk")[0])
- def getVersionCodename(self):
- return self.runShellCommand("getprop ro.build.version.codename")[0].strip()
+ def get_version_codename(self):
+ return self.run_shell_command("getprop ro.build.version.codename")[0].strip()
- def getDensity(self):
- if "emulator" in self._adbDevice:
- return int(self.runShellCommand("getprop qemu.sf.lcd_density")[0])
+ def get_density(self):
+ if "emulator" in self._serial:
+ return int(self.run_shell_command("getprop qemu.sf.lcd_density")[0])
else:
- return int(self.runShellCommand("getprop ro.sf.lcd_density")[0])
+ return int(self.run_shell_command("getprop ro.sf.lcd_density")[0])
- def getSdkLevel(self):
- return int(self.runShellCommand("getprop ro.build.version.sdk")[0])
+ def get_orientation(self):
+ return int(self.run_shell_command("dumpsys | grep SurfaceOrientation")[0].split()[1])
- def getOrientation(self):
- return int(self.runShellCommand("dumpsys | grep SurfaceOrientation")[0].split()[1])
- # Running dumpsys on the emulator currently yields a SIGSEGV, so don't do it.
- #
- #def getHWType(self):
- # (output, err) = self.runShellCommand("dumpsys | grep android.hardware.type")
- # output = output.strip()
- # return output
-
-def runAdbDevices():
+def enumerate_android_devices(require_prefix=''):
devices = subprocess.check_output(["adb", "devices"])
- devices = devices.split('\n')[1:]
+ if not devices:
+ return []
- deviceSerial = []
+ devices = devices.decode('UTF-8').split('\n')[1:]
+ device_list = []
for device in devices:
- if device is not "":
+ if device is not "" and device.startswith(require_prefix):
info = device.split('\t')
if info[1] == "device":
- deviceSerial.append(info[0])
+ device_list.append(info[0])
- return deviceSerial
-
-if __name__ == '__main__':
- main(sys.argv)
+ return device_list
diff --git a/hostsidetests/theme/avd.py b/hostsidetests/theme/avd.py
new file mode 100644
index 0000000..4c444a21
--- /dev/null
+++ b/hostsidetests/theme/avd.py
@@ -0,0 +1,81 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import functools
+import math
+import socket
+import subprocess
+import sys
+import tempfile
+
+from android_device import *
+
+
+def find_free_port():
+ s = socket.socket()
+ s.bind(('', 0))
+ return int(s.getsockname()[1])
+
+
+class AVD(object):
+ def __init__(self, name, emu_path):
+ self._name = name
+ self._emu_path = emu_path
+ self._opts = ''
+ self._adb_name = None
+ self._emu_proc = None
+
+ def start(self):
+ if self._emu_proc:
+ raise Exception('Emulator already running')
+
+ port_adb = find_free_port()
+ port_tty = find_free_port()
+ # -no-window might be useful here
+ emu_cmd = "%s -avd %s %s-ports %d,%d" \
+ % (self._emu_path, self._name, self._opts, port_adb, port_tty)
+ print(emu_cmd)
+
+ emu_proc = subprocess.Popen(emu_cmd.split(" "), bufsize=-1, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+
+ # The emulator ought to be starting now.
+ self._adb_name = "emulator-%d" % (port_tty - 1)
+ self._emu_proc = emu_proc
+
+ def stop(self):
+ if not self._emu_proc:
+ raise Exception('Emulator not currently running')
+ self._emu_proc.kill()
+ (out, err) = self._emu_proc.communicate()
+ self._emu_proc = None
+ return out, err
+
+ def get_serial(self):
+ if not self._emu_proc:
+ raise Exception('Emulator not currently running')
+ return self._adb_name
+
+ def get_device(self):
+ if not self._emu_proc:
+ raise Exception('Emulator not currently running')
+ return AndroidDevice(self._adb_name)
+
+ def configure_screen(self, density, width_dp, height_dp):
+ width_px = int(math.ceil(width_dp * density / 1600) * 10)
+ height_px = int(math.ceil(height_dp * density / 1600) * 10)
+ self._opts = "-prop qemu.sf.lcd_density=%d -skin %dx%d " % (density, width_px, height_px)
diff --git a/hostsidetests/theme/generate_images.py b/hostsidetests/theme/generate_images.py
new file mode 100755
index 0000000..125a0b0
--- /dev/null
+++ b/hostsidetests/theme/generate_images.py
@@ -0,0 +1,238 @@
+#!/usr/bin/python3
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import os
+import sys
+import tempfile
+import threading
+import time
+import traceback
+
+from android_device import *
+from avd import *
+from queue import Queue, Empty
+
+
+CTS_THEME_dict = {
+ 120: "ldpi",
+ 160: "mdpi",
+ 213: "tvdpi",
+ 240: "hdpi",
+ 320: "xhdpi",
+ 360: "360dpi",
+ 420: "420dpi",
+ 480: "xxhdpi",
+ 560: "560dpi",
+ 640: "xxxhdpi",
+}
+
+OUT_FILE = "/sdcard/cts-theme-assets.zip"
+
+
+class ParallelExecutor(threading.Thread):
+ def __init__(self, tasks, q):
+ threading.Thread.__init__(self)
+ self._q = q
+ self._tasks = tasks
+ self._setup = setup
+ self._result = 0
+
+ def run(self):
+ try:
+ while True:
+ config = q.get(block=True, timeout=2)
+ for t in self._tasks:
+ try:
+ if t(self._setup, config):
+ self._result += 1
+ except KeyboardInterrupt:
+ raise
+ except:
+ print("Failed to execute thread:", sys.exc_info()[0])
+ traceback.print_exc()
+ q.task_done()
+ except KeyboardInterrupt:
+ raise
+ except Empty:
+ pass
+
+ def get_result(self):
+ return self._result
+
+
+# pass a function with number of instances to be executed in parallel
+# each thread continues until config q is empty.
+def execute_parallel(tasks, setup, q, num_threads):
+ result = 0
+ threads = []
+ for i in range(num_threads):
+ t = ParallelExecutor(tasks, q)
+ t.start()
+ threads.append(t)
+ for t in threads:
+ t.join()
+ result += t.get_result()
+ return result
+
+
+def print_adb_result(device, out, err):
+ print("device: " + device)
+ if out is not None:
+ print("out:\n" + out)
+ if err is not None:
+ print("err:\n" + err)
+
+
+def do_capture(setup, device_serial):
+ (themeApkPath, out_path) = setup
+
+ device = AndroidDevice(device_serial)
+
+ version = device.get_version_codename()
+ if version == "REL":
+ version = str(device.get_version_sdk())
+
+ density = device.get_density()
+
+ if CTS_THEME_dict[density]:
+ density_bucket = CTS_THEME_dict[density]
+ else:
+ density_bucket = str(density) + "dpi"
+
+ out_file = os.path.join(out_path, os.path.join(version, "%s.zip" % density_bucket))
+
+ device.uninstall_package('android.theme.app')
+
+ (out, err, success) = device.install_apk(themeApkPath)
+ if not success:
+ print("Failed to install APK on " + device_serial)
+ print_adb_result(device_serial, out, err)
+ return False
+
+ print("Generating images on " + device_serial + "...")
+ try:
+ (out, err) = device.run_instrumentation_test(
+ "android.theme.app/android.support.test.runner.AndroidJUnitRunner")
+ except KeyboardInterrupt:
+ raise
+ except:
+ (out, err) = device.run_instrumentation_test(
+ "android.theme.app/android.test.InstrumentationTestRunner")
+
+ # Detect test failure and abort.
+ if "FAILURES!!!" in out.split():
+ print_adb_result(device_serial, out, err)
+ return False
+
+ # Make sure that the run is complete by checking the process itself
+ print("Waiting for " + device_serial + "...")
+ wait_time = 0
+ while device.is_process_alive("android.theme.app"):
+ time.sleep(1)
+ wait_time = wait_time + 1
+ if wait_time > 180:
+ print("Timed out")
+ break
+
+ time.sleep(10)
+
+ print("Pulling images from " + device_serial + " to " + out_file)
+ device.run_adb_command("pull " + OUT_FILE + " " + out_file)
+ device.run_adb_command("shell rm -rf " + OUT_FILE)
+ return True
+
+
+def get_emulator_path():
+ if 'ANDROID_SDK_ROOT' not in os.environ:
+ print('Environment variable ANDROID_SDK_ROOT must point to your Android SDK root.')
+ sys.exit(1)
+
+ sdk_path = os.environ['ANDROID_SDK_ROOT']
+ if not os.path.isdir(sdk_path):
+ print("Failed to find Android SDK at ANDROID_SDK_ROOT: %s" % sdk_path)
+ sys.exit(1)
+
+ emu_path = os.path.join(os.path.join(sdk_path, 'tools'), 'emulator')
+ if not os.path.isfile(emu_path):
+ print("Failed to find emulator within ANDROID_SDK_ROOT: %s" % sdk_path)
+ sys.exit(1)
+
+ return emu_path
+
+
+def start_emulator(name, density):
+ emu_path = get_emulator_path()
+
+ # Start emulator for 560dpi, normal screen size.
+ test_avd = AVD(name, emu_path)
+ test_avd.configure_screen(density, 360, 640)
+ test_avd.start()
+ try:
+ test_avd_device = test_avd.get_device()
+ test_avd_device.wait_for_device()
+ test_avd_device.wait_for_boot_complete()
+ return test_avd
+ except:
+ test_avd.stop()
+ return None
+
+
+def main(argv):
+ if 'ANDROID_BUILD_TOP' not in os.environ or 'ANDROID_HOST_OUT' not in os.environ:
+ print('Missing environment variables. Did you run build/envsetup.sh and lunch?')
+ sys.exit(1)
+
+ theme_apk = os.path.join(os.environ['ANDROID_HOST_OUT'],
+ 'cts/android-cts/testcases/CtsThemeDeviceApp.apk')
+ if not os.path.isfile(theme_apk):
+ print('Couldn\'t find test APK. Did you run make cts?')
+ sys.exit(1)
+
+ out_path = os.path.join(os.environ['ANDROID_BUILD_TOP'],
+ 'cts/hostsidetests/theme/assets')
+ os.system("mkdir -p %s" % out_path)
+
+ if len(argv) is 2:
+ for density in CTS_THEME_dict.keys():
+ emulator = start_emulator(argv[1], density)
+ result = do_capture(setup=(theme_apk, out_path), device_serial=emulator.get_serial())
+ emulator.stop()
+ if result:
+ print("Generated reference images for %ddpi" % density)
+ else:
+ print("Failed to generate reference images for %ddpi" % density)
+ break
+ else:
+ tasks = [do_capture]
+ setup = (theme_apk, out_path)
+
+ devices = enumerate_android_devices('emulator')
+
+ device_queue = Queue()
+ for device in devices:
+ device_queue.put(device)
+
+ result = execute_parallel(tasks, setup, device_queue, len(devices))
+
+ if result > 0:
+ print('Generated reference images for %(count)d devices' % {"count": result})
+ else:
+ print('Failed to generate reference images')
+
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/hostsidetests/theme/generate_images.sh b/hostsidetests/theme/generate_images.sh
deleted file mode 100755
index 129efc8..0000000
--- a/hostsidetests/theme/generate_images.sh
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# This script is used to generate reference images for the CTS theme tests.
-# See the accompanying README file for more information.
-
-# retry <command> <tries> <message> <delay>
-function retry {
- RETRY="0"
- while true; do
- if (("$RETRY" >= "$2")); then
- echo $OUTPUT
- exit
- fi
-
- OUTPUT=`$1 |& grep error`
-
- if [ -z "$OUTPUT" ]; then
- break
- fi
-
- echo $3
- sleep $4
- RETRY=$[$RETRY + 1]
- done
-}
-
-themeApkPath="$ANDROID_HOST_OUT/cts/android-cts/testcases/CtsThemeDeviceApp.apk"
-outDir="$ANDROID_BUILD_TOP/cts/hostsidetests/theme/assets"
-exe="$ANDROID_BUILD_TOP/cts/hostsidetests/theme/run_theme_capture_device.py"
-
-if [ -z "$ANDROID_BUILD_TOP" ]; then
- echo "Missing environment variables. Did you run build/envsetup.sh and lunch?"
- exit
-fi
-
-if [ ! -e "$themeApkPath" ]; then
- echo "Couldn't find test APK. Did you run make cts?"
- exit
-fi
-
-adb devices
-python $exe $themeApkPath $outDir
diff --git a/hostsidetests/theme/run_theme_capture_device.py b/hostsidetests/theme/run_theme_capture_device.py
deleted file mode 100755
index d37864f..0000000
--- a/hostsidetests/theme/run_theme_capture_device.py
+++ /dev/null
@@ -1,180 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the 'License');
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an 'AS IS' BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-import os
-import sys
-import threading
-import time
-import traceback
-import Queue
-sys.path.append(sys.path[0])
-from android_device import *
-
-CTS_THEME_dict = {
- 120 : "ldpi",
- 160 : "mdpi",
- 240 : "hdpi",
- 320 : "xhdpi",
- 480 : "xxhdpi",
- 640 : "xxxhdpi",
-}
-
-OUT_FILE = "/sdcard/cts-theme-assets.zip"
-
-# pass a function with number of instances to be executed in parallel
-# each thread continues until config q is empty.
-def executeParallel(tasks, setup, q, numberThreads):
- class ParallelExecutor(threading.Thread):
- def __init__(self, tasks, q):
- threading.Thread.__init__(self)
- self._q = q
- self._tasks = tasks
- self._setup = setup
- self._result = 0
-
- def run(self):
- try:
- while True:
- config = q.get(block=True, timeout=2)
- for t in self._tasks:
- try:
- if t(self._setup, config):
- self._result += 1
- except KeyboardInterrupt:
- raise
- except:
- print "Failed to execute thread:", sys.exc_info()[0]
- traceback.print_exc()
- q.task_done()
- except KeyboardInterrupt:
- raise
- except Queue.Empty:
- pass
-
- def getResult(self):
- return self._result
-
- result = 0;
- threads = []
- for i in range(numberThreads):
- t = ParallelExecutor(tasks, q)
- t.start()
- threads.append(t)
- for t in threads:
- t.join()
- result += t.getResult()
- return result;
-
-def printAdbResult(device, out, err):
- print "device: " + device
- if out is not None:
- print "out:\n" + out
- if err is not None:
- print "err:\n" + err
-
-def getResDir(outPath, resName):
- resDir = outPath + "/" + resName
- return resDir
-
-def doCapturing(setup, deviceSerial):
- (themeApkPath, outPath) = setup
-
- print "Found device: " + deviceSerial
- device = androidDevice(deviceSerial)
-
- version = device.getVersionCodename()
- if version == "REL":
- version = str(device.getVersionSdkInt())
-
- density = device.getDensity()
-
- # Reference images generated for tv should not be categorized by density
- # rather by tv type. This is because TV uses leanback-specific material
- # themes.
- if CTS_THEME_dict.has_key(density):
- densityBucket = CTS_THEME_dict[density]
- else:
- densityBucket = str(density) + "dpi"
-
- resName = os.path.join(version, densityBucket)
-
- device.uninstallApk("android.theme.app")
-
- (out, err, success) = device.installApk(themeApkPath)
- if not success:
- print "Failed to install APK on " + deviceSerial
- printAdbResult(deviceSerial, out, err)
- return False
-
- print "Generating images on " + deviceSerial + "..."
- try:
- (out, err) = device.runInstrumentationTest("android.theme.app/android.support.test.runner.AndroidJUnitRunner")
- except KeyboardInterrupt:
- raise
- except:
- (out, err) = device.runInstrumentationTest("android.theme.app/android.test.InstrumentationTestRunner")
-
- # Detect test failure and abort.
- if "FAILURES!!!" in out.split():
- printAdbResult(deviceSerial, out, err)
- return False
-
- # Make sure that the run is complete by checking the process itself
- print "Waiting for " + deviceSerial + "..."
- waitTime = 0
- while device.isProcessAlive("android.theme.app"):
- time.sleep(1)
- waitTime = waitTime + 1
- if waitTime > 180:
- print "Timed out"
- break
-
- time.sleep(10)
- resDir = getResDir(outPath, resName)
-
- print "Pulling images from " + deviceSerial + " to " + resDir + ".zip"
- device.runAdbCommand("pull " + OUT_FILE + " " + resDir + ".zip")
- device.runAdbCommand("shell rm -rf " + OUT_FILE)
- return True
-
-def main(argv):
- if len(argv) < 3:
- print "run_theme_capture_device.py themeApkPath outDir"
- sys.exit(1)
- themeApkPath = argv[1]
- outPath = os.path.abspath(argv[2])
- os.system("mkdir -p " + outPath)
-
- tasks = []
- tasks.append(doCapturing)
-
- devices = runAdbDevices();
- numberThreads = len(devices)
-
- configQ = Queue.Queue()
- for device in devices:
- configQ.put(device)
- setup = (themeApkPath, outPath)
- result = executeParallel(tasks, setup, configQ, numberThreads)
-
- if result > 0:
- print 'Generated reference images for %(count)d devices' % {"count": result}
- else:
- print 'Failed to generate reference images'
-
-if __name__ == '__main__':
- main(sys.argv)