1 #!/usr/bin/env python 2 # 3 # Copyright (C) 2015 The Android Open Source Project 4 # 5 # Licensed under the Apache License, Version 2.0 (the 'License'); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an 'AS IS' BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 # 17 18 import os 19 import sys 20 import threading 21 import time 22 import traceback 23 import Queue 24 sys.path.append(sys.path[0]) 25 from android_device import * 26 27 CTS_THEME_dict = { 28 120 : "ldpi", 29 160 : "mdpi", 30 240 : "hdpi", 31 320 : "xhdpi", 32 480 : "xxhdpi", 33 640 : "xxxhdpi", 34 } 35 36 OUT_FILE = "/sdcard/cts-theme-assets.zip" 37 38 # pass a function with number of instances to be executed in parallel 39 # each thread continues until config q is empty. 40 def executeParallel(tasks, setup, q, numberThreads): 41 class ParallelExecutor(threading.Thread): 42 def __init__(self, tasks, q): 43 threading.Thread.__init__(self) 44 self._q = q 45 self._tasks = tasks 46 self._setup = setup 47 self._result = 0 48 49 def run(self): 50 try: 51 while True: 52 config = q.get(block=True, timeout=2) 53 for t in self._tasks: 54 try: 55 if t(self._setup, config): 56 self._result += 1 57 except KeyboardInterrupt: 58 raise 59 except: 60 print "Failed to execute thread:", sys.exc_info()[0] 61 traceback.print_exc() 62 q.task_done() 63 except KeyboardInterrupt: 64 raise 65 except Queue.Empty: 66 pass 67 68 def getResult(self): 69 return self._result 70 71 result = 0; 72 threads = [] 73 for i in range(numberThreads): 74 t = ParallelExecutor(tasks, q) 75 t.start() 76 threads.append(t) 77 for t in threads: 78 t.join() 79 result += t.getResult() 80 return result; 81 82 def printAdbResult(device, out, err): 83 print "device: " + device 84 if out is not None: 85 print "out:\n" + out 86 if err is not None: 87 print "err:\n" + err 88 89 def getResDir(outPath, resName): 90 resDir = outPath + "/" + resName 91 return resDir 92 93 def doCapturing(setup, deviceSerial): 94 (themeApkPath, outPath) = setup 95 96 print "Found device: " + deviceSerial 97 device = androidDevice(deviceSerial) 98 99 version = device.getVersionCodename() 100 if version == "REL": 101 version = str(device.getVersionSdkInt()) 102 103 density = device.getDensity() 104 105 # Reference images generated for tv should not be categorized by density 106 # rather by tv type. This is because TV uses leanback-specific material 107 # themes. 108 if CTS_THEME_dict.has_key(density): 109 densityBucket = CTS_THEME_dict[density] 110 else: 111 densityBucket = str(density) + "dpi" 112 113 resName = os.path.join(version, densityBucket) 114 115 device.uninstallApk("android.theme.app") 116 117 (out, err, success) = device.installApk(themeApkPath) 118 if not success: 119 print "Failed to install APK on " + deviceSerial 120 printAdbResult(deviceSerial, out, err) 121 return False 122 123 print "Generating images on " + deviceSerial + "..." 124 try: 125 (out, err) = device.runInstrumentationTest("android.theme.app/android.support.test.runner.AndroidJUnitRunner") 126 except KeyboardInterrupt: 127 raise 128 except: 129 (out, err) = device.runInstrumentationTest("android.theme.app/android.test.InstrumentationTestRunner") 130 131 # Detect test failure and abort. 132 if "FAILURES!!!" in out.split(): 133 printAdbResult(deviceSerial, out, err) 134 return False 135 136 # Make sure that the run is complete by checking the process itself 137 print "Waiting for " + deviceSerial + "..." 138 waitTime = 0 139 while device.isProcessAlive("android.theme.app"): 140 time.sleep(1) 141 waitTime = waitTime + 1 142 if waitTime > 180: 143 print "Timed out" 144 break 145 146 time.sleep(10) 147 resDir = getResDir(outPath, resName) 148 149 print "Pulling images from " + deviceSerial + " to " + resDir + ".zip" 150 device.runAdbCommand("pull " + OUT_FILE + " " + resDir + ".zip") 151 device.runAdbCommand("shell rm -rf " + OUT_FILE) 152 return True 153 154 def main(argv): 155 if len(argv) < 3: 156 print "run_theme_capture_device.py themeApkPath outDir" 157 sys.exit(1) 158 themeApkPath = argv[1] 159 outPath = os.path.abspath(argv[2]) 160 os.system("mkdir -p " + outPath) 161 162 tasks = [] 163 tasks.append(doCapturing) 164 165 devices = runAdbDevices(); 166 numberThreads = len(devices) 167 168 configQ = Queue.Queue() 169 for device in devices: 170 configQ.put(device) 171 setup = (themeApkPath, outPath) 172 result = executeParallel(tasks, setup, configQ, numberThreads) 173 174 if result > 0: 175 print 'Generated reference images for %(count)d devices' % {"count": result} 176 else: 177 print 'Failed to generate reference images' 178 179 if __name__ == '__main__': 180 main(sys.argv) 181