xref: /aosp_15_r20/cts/hostsidetests/theme/generate_images.py (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
1*b7c941bbSAndroid Build Coastguard Worker#!/usr/bin/python3
2*b7c941bbSAndroid Build Coastguard Worker#
3*b7c941bbSAndroid Build Coastguard Worker# Copyright (C) 2015 The Android Open Source Project
4*b7c941bbSAndroid Build Coastguard Worker#
5*b7c941bbSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the 'License');
6*b7c941bbSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*b7c941bbSAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*b7c941bbSAndroid Build Coastguard Worker#
9*b7c941bbSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
10*b7c941bbSAndroid Build Coastguard Worker#
11*b7c941bbSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*b7c941bbSAndroid Build Coastguard Worker# distributed under the License is distributed on an 'AS IS' BASIS,
13*b7c941bbSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*b7c941bbSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*b7c941bbSAndroid Build Coastguard Worker# limitations under the License.
16*b7c941bbSAndroid Build Coastguard Worker#
17*b7c941bbSAndroid Build Coastguard Worker
18*b7c941bbSAndroid Build Coastguard Workerimport os
19*b7c941bbSAndroid Build Coastguard Workerimport sys
20*b7c941bbSAndroid Build Coastguard Workerimport tempfile
21*b7c941bbSAndroid Build Coastguard Workerimport threading
22*b7c941bbSAndroid Build Coastguard Workerimport time
23*b7c941bbSAndroid Build Coastguard Workerimport traceback
24*b7c941bbSAndroid Build Coastguard Worker
25*b7c941bbSAndroid Build Coastguard Workerfrom android_device import *
26*b7c941bbSAndroid Build Coastguard Workerfrom avd import *
27*b7c941bbSAndroid Build Coastguard Workerfrom queue import Queue, Empty
28*b7c941bbSAndroid Build Coastguard Worker
29*b7c941bbSAndroid Build Coastguard Worker
30*b7c941bbSAndroid Build Coastguard Worker# This dict should contain one entry for every density listed in DisplayMetrics.
31*b7c941bbSAndroid Build Coastguard Worker# See CDD 7.1.1.3 for more information on densities at which CTS can run. If you
32*b7c941bbSAndroid Build Coastguard Worker# are only generating reference images for a single density, you can comment out
33*b7c941bbSAndroid Build Coastguard Worker# the other densities and then run the script.
34*b7c941bbSAndroid Build Coastguard WorkerCTS_THEME_dict = {
35*b7c941bbSAndroid Build Coastguard Worker    120: "ldpi",
36*b7c941bbSAndroid Build Coastguard Worker    140: "140dpi",
37*b7c941bbSAndroid Build Coastguard Worker    160: "mdpi",
38*b7c941bbSAndroid Build Coastguard Worker    180: "180dpi",
39*b7c941bbSAndroid Build Coastguard Worker    200: "200dpi",
40*b7c941bbSAndroid Build Coastguard Worker    213: "tvdpi",
41*b7c941bbSAndroid Build Coastguard Worker    220: "220dpi",
42*b7c941bbSAndroid Build Coastguard Worker    240: "hdpi",
43*b7c941bbSAndroid Build Coastguard Worker    260: "260dpi",
44*b7c941bbSAndroid Build Coastguard Worker    280: "280dpi",
45*b7c941bbSAndroid Build Coastguard Worker    300: "300dpi",
46*b7c941bbSAndroid Build Coastguard Worker    320: "xhdpi",
47*b7c941bbSAndroid Build Coastguard Worker    340: "340dpi",
48*b7c941bbSAndroid Build Coastguard Worker    360: "360dpi",
49*b7c941bbSAndroid Build Coastguard Worker    390: "390dpi",
50*b7c941bbSAndroid Build Coastguard Worker    400: "400dpi",
51*b7c941bbSAndroid Build Coastguard Worker    420: "420dpi",
52*b7c941bbSAndroid Build Coastguard Worker    440: "440dpi",
53*b7c941bbSAndroid Build Coastguard Worker    450: "450dpi",
54*b7c941bbSAndroid Build Coastguard Worker    480: "xxhdpi",
55*b7c941bbSAndroid Build Coastguard Worker    520: "520dpi",
56*b7c941bbSAndroid Build Coastguard Worker    560: "560dpi",
57*b7c941bbSAndroid Build Coastguard Worker    600: "600dpi",
58*b7c941bbSAndroid Build Coastguard Worker    640: "xxxhdpi",
59*b7c941bbSAndroid Build Coastguard Worker}
60*b7c941bbSAndroid Build Coastguard Worker
61*b7c941bbSAndroid Build Coastguard WorkerOUT_FILE = "/sdcard/cts-theme-assets.zip"
62*b7c941bbSAndroid Build Coastguard Worker
63*b7c941bbSAndroid Build Coastguard Worker
64*b7c941bbSAndroid Build Coastguard Workerclass ParallelExecutor(threading.Thread):
65*b7c941bbSAndroid Build Coastguard Worker    def __init__(self, tasks, setup, q):
66*b7c941bbSAndroid Build Coastguard Worker        threading.Thread.__init__(self)
67*b7c941bbSAndroid Build Coastguard Worker        self._q = q
68*b7c941bbSAndroid Build Coastguard Worker        self._tasks = tasks
69*b7c941bbSAndroid Build Coastguard Worker        self._setup = setup
70*b7c941bbSAndroid Build Coastguard Worker        self._result = 0
71*b7c941bbSAndroid Build Coastguard Worker
72*b7c941bbSAndroid Build Coastguard Worker    def run(self):
73*b7c941bbSAndroid Build Coastguard Worker        try:
74*b7c941bbSAndroid Build Coastguard Worker            while True:
75*b7c941bbSAndroid Build Coastguard Worker                config = self._q.get(block=True, timeout=2)
76*b7c941bbSAndroid Build Coastguard Worker                for t in self._tasks:
77*b7c941bbSAndroid Build Coastguard Worker                    try:
78*b7c941bbSAndroid Build Coastguard Worker                        if t(self._setup, config):
79*b7c941bbSAndroid Build Coastguard Worker                            self._result += 1
80*b7c941bbSAndroid Build Coastguard Worker                    except KeyboardInterrupt:
81*b7c941bbSAndroid Build Coastguard Worker                        raise
82*b7c941bbSAndroid Build Coastguard Worker                    except:
83*b7c941bbSAndroid Build Coastguard Worker                        print("Failed to execute thread:", sys.exc_info()[0])
84*b7c941bbSAndroid Build Coastguard Worker                        traceback.print_exc()
85*b7c941bbSAndroid Build Coastguard Worker                self._q.task_done()
86*b7c941bbSAndroid Build Coastguard Worker        except KeyboardInterrupt:
87*b7c941bbSAndroid Build Coastguard Worker            raise
88*b7c941bbSAndroid Build Coastguard Worker        except Empty:
89*b7c941bbSAndroid Build Coastguard Worker            pass
90*b7c941bbSAndroid Build Coastguard Worker
91*b7c941bbSAndroid Build Coastguard Worker    def get_result(self):
92*b7c941bbSAndroid Build Coastguard Worker        return self._result
93*b7c941bbSAndroid Build Coastguard Worker
94*b7c941bbSAndroid Build Coastguard Worker
95*b7c941bbSAndroid Build Coastguard Worker# pass a function with number of instances to be executed in parallel
96*b7c941bbSAndroid Build Coastguard Worker# each thread continues until config q is empty.
97*b7c941bbSAndroid Build Coastguard Workerdef execute_parallel(tasks, setup, q, num_threads):
98*b7c941bbSAndroid Build Coastguard Worker    result = 0
99*b7c941bbSAndroid Build Coastguard Worker    threads = []
100*b7c941bbSAndroid Build Coastguard Worker    for i in range(num_threads):
101*b7c941bbSAndroid Build Coastguard Worker        t = ParallelExecutor(tasks, setup, q)
102*b7c941bbSAndroid Build Coastguard Worker        t.start()
103*b7c941bbSAndroid Build Coastguard Worker        threads.append(t)
104*b7c941bbSAndroid Build Coastguard Worker    for t in threads:
105*b7c941bbSAndroid Build Coastguard Worker        t.join()
106*b7c941bbSAndroid Build Coastguard Worker        result += t.get_result()
107*b7c941bbSAndroid Build Coastguard Worker    return result
108*b7c941bbSAndroid Build Coastguard Worker
109*b7c941bbSAndroid Build Coastguard Worker
110*b7c941bbSAndroid Build Coastguard Workerdef print_adb_result(device, out, err):
111*b7c941bbSAndroid Build Coastguard Worker    print("device: " + device)
112*b7c941bbSAndroid Build Coastguard Worker    if out is not None:
113*b7c941bbSAndroid Build Coastguard Worker        print("out:\n" + out)
114*b7c941bbSAndroid Build Coastguard Worker    if err is not None:
115*b7c941bbSAndroid Build Coastguard Worker        print("err:\n" + err)
116*b7c941bbSAndroid Build Coastguard Worker
117*b7c941bbSAndroid Build Coastguard Worker
118*b7c941bbSAndroid Build Coastguard Workerdef do_capture(setup, device_serial):
119*b7c941bbSAndroid Build Coastguard Worker    (themeApkPath, out_path) = setup
120*b7c941bbSAndroid Build Coastguard Worker
121*b7c941bbSAndroid Build Coastguard Worker    device = AndroidDevice(device_serial)
122*b7c941bbSAndroid Build Coastguard Worker
123*b7c941bbSAndroid Build Coastguard Worker    version = device.get_version_codename()
124*b7c941bbSAndroid Build Coastguard Worker    if version == "REL":
125*b7c941bbSAndroid Build Coastguard Worker        version = str(device.get_version_sdk())
126*b7c941bbSAndroid Build Coastguard Worker
127*b7c941bbSAndroid Build Coastguard Worker    density = device.get_density()
128*b7c941bbSAndroid Build Coastguard Worker
129*b7c941bbSAndroid Build Coastguard Worker    if CTS_THEME_dict[density]:
130*b7c941bbSAndroid Build Coastguard Worker        density_bucket = CTS_THEME_dict[density]
131*b7c941bbSAndroid Build Coastguard Worker    else:
132*b7c941bbSAndroid Build Coastguard Worker        density_bucket = str(density) + "dpi"
133*b7c941bbSAndroid Build Coastguard Worker
134*b7c941bbSAndroid Build Coastguard Worker    out_file = os.path.join(out_path, os.path.join(version, "%s.zip" % density_bucket))
135*b7c941bbSAndroid Build Coastguard Worker
136*b7c941bbSAndroid Build Coastguard Worker    device.uninstall_package('android.theme.app')
137*b7c941bbSAndroid Build Coastguard Worker
138*b7c941bbSAndroid Build Coastguard Worker    (out, err, success) = device.install_apk(themeApkPath)
139*b7c941bbSAndroid Build Coastguard Worker    if not success:
140*b7c941bbSAndroid Build Coastguard Worker        print("Failed to install APK on " + device_serial)
141*b7c941bbSAndroid Build Coastguard Worker        print_adb_result(device_serial, out, err)
142*b7c941bbSAndroid Build Coastguard Worker        return False
143*b7c941bbSAndroid Build Coastguard Worker
144*b7c941bbSAndroid Build Coastguard Worker    print("Generating images on " + device_serial + "...")
145*b7c941bbSAndroid Build Coastguard Worker    try:
146*b7c941bbSAndroid Build Coastguard Worker        (out, err) = device.run_instrumentation_test(
147*b7c941bbSAndroid Build Coastguard Worker            "android.theme.app/androidx.test.runner.AndroidJUnitRunner")
148*b7c941bbSAndroid Build Coastguard Worker    except KeyboardInterrupt:
149*b7c941bbSAndroid Build Coastguard Worker        raise
150*b7c941bbSAndroid Build Coastguard Worker    except:
151*b7c941bbSAndroid Build Coastguard Worker        (out, err) = device.run_instrumentation_test(
152*b7c941bbSAndroid Build Coastguard Worker            "android.theme.app/android.test.InstrumentationTestRunner")
153*b7c941bbSAndroid Build Coastguard Worker
154*b7c941bbSAndroid Build Coastguard Worker    # Detect test failure and abort.
155*b7c941bbSAndroid Build Coastguard Worker    if "FAILURES!!!" in out.split():
156*b7c941bbSAndroid Build Coastguard Worker        print_adb_result(device_serial, out, err)
157*b7c941bbSAndroid Build Coastguard Worker        return False
158*b7c941bbSAndroid Build Coastguard Worker
159*b7c941bbSAndroid Build Coastguard Worker    # Make sure that the run is complete by checking the process itself
160*b7c941bbSAndroid Build Coastguard Worker    print("Waiting for " + device_serial + "...")
161*b7c941bbSAndroid Build Coastguard Worker    wait_time = 0
162*b7c941bbSAndroid Build Coastguard Worker    while device.is_process_alive("android.theme.app"):
163*b7c941bbSAndroid Build Coastguard Worker        time.sleep(1)
164*b7c941bbSAndroid Build Coastguard Worker        wait_time = wait_time + 1
165*b7c941bbSAndroid Build Coastguard Worker        if wait_time > 180:
166*b7c941bbSAndroid Build Coastguard Worker            print("Timed out")
167*b7c941bbSAndroid Build Coastguard Worker            break
168*b7c941bbSAndroid Build Coastguard Worker
169*b7c941bbSAndroid Build Coastguard Worker    time.sleep(10)
170*b7c941bbSAndroid Build Coastguard Worker
171*b7c941bbSAndroid Build Coastguard Worker    print("Pulling images from " + device_serial + " to " + out_file)
172*b7c941bbSAndroid Build Coastguard Worker    device.run_adb_command("pull " + OUT_FILE + " " + out_file)
173*b7c941bbSAndroid Build Coastguard Worker    device.run_adb_command("shell rm -rf " + OUT_FILE)
174*b7c941bbSAndroid Build Coastguard Worker    return True
175*b7c941bbSAndroid Build Coastguard Worker
176*b7c941bbSAndroid Build Coastguard Worker
177*b7c941bbSAndroid Build Coastguard Workerdef get_emulator_path():
178*b7c941bbSAndroid Build Coastguard Worker    if 'ANDROID_SDK_ROOT' not in os.environ:
179*b7c941bbSAndroid Build Coastguard Worker        print('Environment variable ANDROID_SDK_ROOT must point to your Android SDK root.')
180*b7c941bbSAndroid Build Coastguard Worker        sys.exit(1)
181*b7c941bbSAndroid Build Coastguard Worker
182*b7c941bbSAndroid Build Coastguard Worker    sdk_path = os.environ['ANDROID_SDK_ROOT']
183*b7c941bbSAndroid Build Coastguard Worker    if not os.path.isdir(sdk_path):
184*b7c941bbSAndroid Build Coastguard Worker        print("Failed to find Android SDK at ANDROID_SDK_ROOT: %s" % sdk_path)
185*b7c941bbSAndroid Build Coastguard Worker        sys.exit(1)
186*b7c941bbSAndroid Build Coastguard Worker
187*b7c941bbSAndroid Build Coastguard Worker    emu_path = os.path.join(os.path.join(sdk_path, 'tools'), 'emulator')
188*b7c941bbSAndroid Build Coastguard Worker    if not os.path.isfile(emu_path):
189*b7c941bbSAndroid Build Coastguard Worker        print("Failed to find emulator within ANDROID_SDK_ROOT: %s" % sdk_path)
190*b7c941bbSAndroid Build Coastguard Worker        sys.exit(1)
191*b7c941bbSAndroid Build Coastguard Worker
192*b7c941bbSAndroid Build Coastguard Worker    return emu_path
193*b7c941bbSAndroid Build Coastguard Worker
194*b7c941bbSAndroid Build Coastguard Worker
195*b7c941bbSAndroid Build Coastguard Workerdef start_emulator(name, density):
196*b7c941bbSAndroid Build Coastguard Worker    if name == "local":
197*b7c941bbSAndroid Build Coastguard Worker        emu_path = ""
198*b7c941bbSAndroid Build Coastguard Worker    else:
199*b7c941bbSAndroid Build Coastguard Worker        emu_path = get_emulator_path()
200*b7c941bbSAndroid Build Coastguard Worker
201*b7c941bbSAndroid Build Coastguard Worker    # Start emulator for 560dpi, normal screen size.
202*b7c941bbSAndroid Build Coastguard Worker    test_avd = AVD(name, emu_path)
203*b7c941bbSAndroid Build Coastguard Worker    test_avd.configure_screen(density, 360, 640)
204*b7c941bbSAndroid Build Coastguard Worker    test_avd.start()
205*b7c941bbSAndroid Build Coastguard Worker    try:
206*b7c941bbSAndroid Build Coastguard Worker        test_avd_device = test_avd.get_device()
207*b7c941bbSAndroid Build Coastguard Worker        test_avd_device.wait_for_device()
208*b7c941bbSAndroid Build Coastguard Worker        test_avd_device.wait_for_boot_complete()
209*b7c941bbSAndroid Build Coastguard Worker        return test_avd
210*b7c941bbSAndroid Build Coastguard Worker    except:
211*b7c941bbSAndroid Build Coastguard Worker        test_avd.stop()
212*b7c941bbSAndroid Build Coastguard Worker        return None
213*b7c941bbSAndroid Build Coastguard Worker
214*b7c941bbSAndroid Build Coastguard Worker
215*b7c941bbSAndroid Build Coastguard Workerdef main(argv):
216*b7c941bbSAndroid Build Coastguard Worker    if 'ANDROID_BUILD_TOP' not in os.environ or 'ANDROID_HOST_OUT' not in os.environ:
217*b7c941bbSAndroid Build Coastguard Worker        print('Missing environment variables. Did you run build/envsetup.sh and lunch?')
218*b7c941bbSAndroid Build Coastguard Worker        sys.exit(1)
219*b7c941bbSAndroid Build Coastguard Worker
220*b7c941bbSAndroid Build Coastguard Worker    theme_apk = os.path.join(os.environ['ANDROID_HOST_OUT'],
221*b7c941bbSAndroid Build Coastguard Worker                             'cts/android-cts/testcases/CtsThemeHostTestCases/CtsThemeDeviceApp.apk')
222*b7c941bbSAndroid Build Coastguard Worker    if not os.path.isfile(theme_apk):
223*b7c941bbSAndroid Build Coastguard Worker        print('Couldn\'t find test APK. Did you run make cts?')
224*b7c941bbSAndroid Build Coastguard Worker        sys.exit(1)
225*b7c941bbSAndroid Build Coastguard Worker
226*b7c941bbSAndroid Build Coastguard Worker    out_path = os.path.join(os.environ['ANDROID_BUILD_TOP'],
227*b7c941bbSAndroid Build Coastguard Worker                            'cts/hostsidetests/theme/assets')
228*b7c941bbSAndroid Build Coastguard Worker    os.system("mkdir -p %s" % out_path)
229*b7c941bbSAndroid Build Coastguard Worker
230*b7c941bbSAndroid Build Coastguard Worker    if len(argv) == 2:
231*b7c941bbSAndroid Build Coastguard Worker        for density in CTS_THEME_dict.keys():
232*b7c941bbSAndroid Build Coastguard Worker            retries = 0
233*b7c941bbSAndroid Build Coastguard Worker            result = False
234*b7c941bbSAndroid Build Coastguard Worker            while result != True:
235*b7c941bbSAndroid Build Coastguard Worker                retries += 1
236*b7c941bbSAndroid Build Coastguard Worker                emulator = start_emulator(argv[1], density)
237*b7c941bbSAndroid Build Coastguard Worker                result = do_capture(setup=(theme_apk, out_path), device_serial=emulator.get_serial())
238*b7c941bbSAndroid Build Coastguard Worker                emulator.stop()
239*b7c941bbSAndroid Build Coastguard Worker                if result:
240*b7c941bbSAndroid Build Coastguard Worker                    print("Generated reference images for %ddpi" % density)
241*b7c941bbSAndroid Build Coastguard Worker                else:
242*b7c941bbSAndroid Build Coastguard Worker                    print("Failed to generate reference images for %ddpi" % density)
243*b7c941bbSAndroid Build Coastguard Worker                    print("Try number %d" % retries)
244*b7c941bbSAndroid Build Coastguard Worker    else:
245*b7c941bbSAndroid Build Coastguard Worker        tasks = [do_capture]
246*b7c941bbSAndroid Build Coastguard Worker        setup = (theme_apk, out_path)
247*b7c941bbSAndroid Build Coastguard Worker
248*b7c941bbSAndroid Build Coastguard Worker        devices = enumerate_android_devices()
249*b7c941bbSAndroid Build Coastguard Worker
250*b7c941bbSAndroid Build Coastguard Worker        if len(devices) > 0:
251*b7c941bbSAndroid Build Coastguard Worker            device_queue = Queue()
252*b7c941bbSAndroid Build Coastguard Worker            for device in devices:
253*b7c941bbSAndroid Build Coastguard Worker                device_queue.put(device)
254*b7c941bbSAndroid Build Coastguard Worker
255*b7c941bbSAndroid Build Coastguard Worker            result = execute_parallel(tasks, setup, device_queue, len(devices))
256*b7c941bbSAndroid Build Coastguard Worker
257*b7c941bbSAndroid Build Coastguard Worker            if result > 0:
258*b7c941bbSAndroid Build Coastguard Worker                print('Generated reference images for %(count)d devices' % {"count": result})
259*b7c941bbSAndroid Build Coastguard Worker            else:
260*b7c941bbSAndroid Build Coastguard Worker                print('Failed to generate reference images')
261*b7c941bbSAndroid Build Coastguard Worker        else:
262*b7c941bbSAndroid Build Coastguard Worker            print('No devices found')
263*b7c941bbSAndroid Build Coastguard Worker
264*b7c941bbSAndroid Build Coastguard Worker
265*b7c941bbSAndroid Build Coastguard Workerif __name__ == '__main__':
266*b7c941bbSAndroid Build Coastguard Worker    main(sys.argv)
267