blob: c9688fb41e99e676da85c93f306c4177226162b1 [file] [log] [blame]
/*
* Copyright (C) 2014 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.
*/
package android.theme.cts;
import com.android.cts.tradefed.build.CtsBuildHelper;
import com.android.ddmlib.Log;
import com.android.ddmlib.Log.LogLevel;
import com.android.ddmlib.IShellOutputReceiver;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceTestCase;
import com.android.tradefed.testtype.IBuildReceiver;
import android.cts.util.TimeoutReq;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.String;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
* Test to check the Holo theme has not been changed.
*/
public class ThemeHostTest extends DeviceTestCase implements IBuildReceiver {
private static final String TAG = ThemeHostTest.class.getSimpleName();
private static final int CAPTURE_TIMEOUT = 500;//0.5sec in ms
private static final int ADB_TIMEOUT = 60 * 60 * 1000;//60mins in ms
/** The package name of the APK. */
private static final String PACKAGE = "android.theme.app";
/** The file name of the APK. */
private static final String APK = "CtsThemeDeviceApp.apk";
/** The class name of the main activity in the APK. */
private static final String CLASS = "HoloDeviceActivity";
/** The command to launch the main activity. */
private static final String START_CMD = String.format(
"am start -W -a android.intent.action.MAIN -n %s/%s.%s", PACKAGE, PACKAGE, CLASS);
private static final String STOP_CMD = String.format("am force-stop %s", PACKAGE);
private static final String DENSITY_PROP_DEVICE = "ro.sf.lcd_density";
private static final String DENSITY_PROP_EMULATOR = "qemu.sf.lcd_density";
// Intent extras
protected final static String INTENT_STRING_EXTRA = " --es %s %s";
protected final static String INTENT_BOOLEAN_EXTRA = " --ez %s %b";
protected final static String INTENT_INTEGER_EXTRA = " --ei %s %d";
// Intent extra keys
private static final String EXTRA_THEME = "holo_theme_extra";
private static final String EXTRA_LAYOUT = "holo_layout_extra";
private static final String EXTRA_TIMEOUT = "holo_timeout_extra";
private static final String[] THEMES = {
"holo",
"holo_dialog",
"holo_dialog_minwidth",
"holo_dialog_noactionbar",
"holo_dialog_noactionbar_minwidth",
"holo_dialogwhenlarge",
"holo_dialogwhenlarge_noactionbar",
"holo_inputmethod",
"holo_light",
"holo_light_darkactionbar",
"holo_light_dialog",
"holo_light_dialog_minwidth",
"holo_light_dialog_noactionbar",
"holo_light_dialog_noactionbar_minwidth",
"holo_light_dialogwhenlarge",
"holo_light_dialogwhenlarge_noactionbar",
"holo_light_noactionbar",
"holo_light_noactionbar_fullscreen",
"holo_light_panel",
"holo_noactionbar",
"holo_noactionbar_fullscreen",
"holo_panel",
"holo_wallpaper",
"holo_wallpaper_notitlebar",
};
private final int NUM_THEMES = THEMES.length;
private static final String[] LAYOUTS = {
"button",
"button_pressed",
"checkbox",
"checkbox_checked",
"chronometer",
"color_blue_bright",
"color_blue_dark",
"color_blue_light",
"color_green_dark",
"color_green_light",
"color_orange_dark",
"color_orange_light",
"color_purple",
"color_red_dark",
"color_red_light",
"datepicker",
"display_info",
"edittext",
"progressbar_horizontal_0",
"progressbar_horizontal_100",
"progressbar_horizontal_50",
"progressbar_large",
"progressbar_small",
"progressbar",
"radiobutton_checked",
"radiobutton",
"radiogroup_horizontal",
"radiogroup_vertical",
"ratingbar_0",
"ratingbar_2point5",
"ratingbar_5",
"ratingbar_0_pressed",
"ratingbar_2point5_pressed",
"ratingbar_5_pressed",
"searchview_query",
"searchview_query_hint",
"seekbar_0",
"seekbar_100",
"seekbar_50",
"spinner",
"switch_button_checked",
"switch_button",
"textview",
"timepicker",
"togglebutton_checked",
"togglebutton",
"zoomcontrols",
};
private final int NUM_LAYOUTS = LAYOUTS.length;
private final HashMap<String, File> mReferences = new HashMap<String, File>();
/** A reference to the build. */
private CtsBuildHelper mBuild;
/** A reference to the device under test. */
private ITestDevice mDevice;
private ExecutorService mExecutionService;
private ExecutorCompletionService<Boolean> mCompletionService;
@Override
public void setBuild(IBuildInfo buildInfo) {
// Get the build, this is used to access the APK.
mBuild = CtsBuildHelper.createBuildHelper(buildInfo);
}
@Override
protected void setUp() throws Exception {
super.setUp();
// Get the device, this gives a handle to run commands and install APKs.
mDevice = getDevice();
// Remove any previously installed versions of this APK.
mDevice.uninstallPackage(PACKAGE);
// Get the APK from the build.
File app = mBuild.getTestApp(APK);
// Install the APK on the device.
mDevice.installPackage(app, false);
final String densityProp;
if (mDevice.getSerialNumber().startsWith("emulator-")) {
densityProp = DENSITY_PROP_EMULATOR;
} else {
densityProp = DENSITY_PROP_DEVICE;
}
final String zip = String.format("/%s.zip",
getDensityBucket(Integer.parseInt(mDevice.getProperty(densityProp))));
Log.logAndDisplay(LogLevel.INFO, TAG, "Loading resources from " + zip);
final InputStream zipStream = this.getClass().getResourceAsStream(zip);
if (zipStream != null) {
final ZipInputStream in = new ZipInputStream(zipStream);
try {
ZipEntry ze;
final byte[] buffer = new byte[1024];
while ((ze = in.getNextEntry()) != null) {
final String name = ze.getName();
final File tmp = File.createTempFile("ref_" + name, ".png");
final FileOutputStream out = new FileOutputStream(tmp);
int count;
while ((count = in.read(buffer)) != -1) {
out.write(buffer, 0, count);
}
out.flush();
out.close();
mReferences.put(name, tmp);
}
} finally {
in.close();
}
}
mExecutionService = Executors.newFixedThreadPool(2);// 2 worker threads
mCompletionService = new ExecutorCompletionService<Boolean>(mExecutionService);
}
@Override
protected void tearDown() throws Exception {
// Delete the temp files
for (File ref : mReferences.values()) {
ref.delete();
}
mExecutionService.shutdown();
// Remove the APK.
mDevice.uninstallPackage(PACKAGE);
super.tearDown();
}
@TimeoutReq(minutes = 60)
public void testHoloThemes() throws Exception {
if (mReferences.isEmpty()) {
Log.logAndDisplay(LogLevel.INFO, TAG,
"Skipped HoloThemes test due to no reference images");
return;
}
int numTasks = 0;
for (int i = 0; i < NUM_THEMES; i++) {
final String themeName = THEMES[i];
for (int j = 0; j < NUM_LAYOUTS; j++) {
final String name = String.format("%s_%s", themeName, LAYOUTS[j]);
if (runCapture(i, j)) {
final File ref = mReferences.get(name + ".png");
if (!ref.exists()) {
Log.logAndDisplay(LogLevel.INFO, TAG,
"Skipping theme test due to missing reference for reference image " + name);
continue;
}
mCompletionService.submit(new ComparisonTask(mDevice, ref, name));
numTasks++;
} else {
Log.logAndDisplay(LogLevel.ERROR, TAG, "Capture failed: " + name);
}
}
}
int failures = 0;
for (int i = 0; i < numTasks; i++) {
failures += mCompletionService.take().get() ? 0 : 1;
}
assertTrue(failures + " failures in theme test", failures == 0);
}
private boolean runCapture(int themeId, int layoutId) throws Exception {
final StringBuilder sb = new StringBuilder(START_CMD);
sb.append(String.format(INTENT_INTEGER_EXTRA, EXTRA_THEME, themeId));
sb.append(String.format(INTENT_INTEGER_EXTRA, EXTRA_LAYOUT, layoutId));
sb.append(String.format(INTENT_INTEGER_EXTRA, EXTRA_TIMEOUT, CAPTURE_TIMEOUT));
final String startCommand = sb.toString();
// Clear logcat
mDevice.executeAdbCommand("logcat", "-c");
// Stop any existing instances
mDevice.executeShellCommand(STOP_CMD);
// Start activity
mDevice.executeShellCommand(startCommand);
boolean success = false;
boolean waiting = true;
while (waiting) {
// Dump logcat.
final String logs = mDevice.executeAdbCommand("logcat", "-d", CLASS + ":I", "*:S");
// Search for string.
final Scanner in = new Scanner(logs);
while (in.hasNextLine()) {
final String line = in.nextLine();
if (line.startsWith("I/" + CLASS)) {
final String s = line.split(":")[1].trim();
if (s.equals("OKAY")) {
success = true;
waiting = false;
} else if (s.equals("ERROR")) {
success = false;
waiting = false;
}
}
}
}
return success;
}
private static String getDensityBucket(int density) {
switch (density) {
case 120:
return "ldpi";
case 160:
return "mdpi";
case 213:
return "tvdpi";
case 240:
return "hdpi";
case 320:
return "xhdpi";
case 400:
return "400dpi";
case 480:
return "xxhdpi";
case 640:
return "xxxhdpi";
default:
return "" + density;
}
}
}