blob: d8b1f3079b1b9457188b59039d11081656b440cc [file] [log] [blame]
/*
* 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.
*/
package android.theme.app;
import android.app.Activity;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.theme.app.modifiers.DatePickerModifier;
import android.theme.app.modifiers.ProgressBarModifier;
import android.theme.app.modifiers.SearchViewModifier;
import android.theme.app.modifiers.TimePickerModifier;
import android.theme.app.modifiers.ViewCheckedModifier;
import android.theme.app.modifiers.ViewPressedModifier;
import android.util.Log;
import android.view.View;
import android.view.WindowManager.LayoutParams;
import android.widget.DatePicker;
import java.io.File;
import java.lang.Override;
/**
* A activity which display various UI elements with non-modifiable themes.
*/
public class ThemeDeviceActivity extends Activity {
public static final String EXTRA_THEME = "theme";
public static final String EXTRA_OUTPUT_DIR = "outputDir";
private static final String TAG = "ThemeDeviceActivity";
/**
* The duration of the CalendarView adjustment to settle to its final
* position.
*/
private static final long CALENDAR_VIEW_ADJUSTMENT_DURATION = 540;
private Theme mTheme;
private ReferenceViewGroup mViewGroup;
private File mOutputDir;
private int mLayoutIndex;
private boolean mIsRunning;
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
final Intent intent = getIntent();
final int themeIndex = intent.getIntExtra(EXTRA_THEME, -1);
if (themeIndex < 0) {
Log.e(TAG, "No theme specified");
finish();
}
final String outputDir = intent.getStringExtra(EXTRA_OUTPUT_DIR);
if (outputDir == null) {
Log.e(TAG, "No output directory specified");
finish();
}
mOutputDir = new File(outputDir);
mTheme = THEMES[themeIndex];
setTheme(mTheme.id);
setContentView(R.layout.theme_test);
mViewGroup = (ReferenceViewGroup) findViewById(R.id.reference_view_group);
getWindow().addFlags(LayoutParams.FLAG_KEEP_SCREEN_ON
| LayoutParams.FLAG_TURN_SCREEN_ON
| LayoutParams.FLAG_DISMISS_KEYGUARD );
}
@Override
protected void onResume() {
super.onResume();
mIsRunning = true;
setNextLayout();
}
@Override
protected void onPause() {
mIsRunning = false;
if (!isFinishing()) {
// The activity paused for some reason, likely a system crash
// dialog. Finish it so we can move to the next theme.
Log.w(TAG, "onPause() called without a call to finish()", new RuntimeException());
finish();
}
super.onPause();
}
@Override
protected void onDestroy() {
if (mLayoutIndex < LAYOUTS.length) {
Log.e(TAG, "Not all layouts got rendered: " + mLayoutIndex);
setResult(RESULT_CANCELED);
}
super.onDestroy();
}
/**
* Sets the next layout in the UI.
*/
private void setNextLayout() {
if (mLayoutIndex >= LAYOUTS.length) {
setResult(RESULT_OK);
finish();
return;
}
mViewGroup.removeAllViews();
final Layout layout = LAYOUTS[mLayoutIndex++];
final String layoutName = String.format("%s_%s", mTheme.name, layout.name);
final View view = getLayoutInflater().inflate(layout.id, mViewGroup, false);
if (layout.modifier != null) {
layout.modifier.modifyView(view);
}
mViewGroup.addView(view);
view.setFocusable(false);
Log.v(TAG, "Rendering layout " + layoutName
+ " (" + mLayoutIndex + "/" + LAYOUTS.length + ")");
final Runnable generateBitmapRunnable = new Runnable() {
@Override
public void run() {
new BitmapTask(view, layoutName).execute();
}
};
if (view instanceof DatePicker) {
// The Holo-styled DatePicker uses a CalendarView that has a
// non-configurable adjustment duration of 540ms.
view.postDelayed(generateBitmapRunnable, CALENDAR_VIEW_ADJUSTMENT_DURATION);
} else {
view.post(generateBitmapRunnable);
}
}
private class BitmapTask extends GenerateBitmapTask {
public BitmapTask(View view, String name) {
super(view, mOutputDir, name);
}
@Override
protected void onPostExecute(Boolean success) {
if (success && mIsRunning) {
setNextLayout();
} else {
Log.e(TAG, "Failed to render view to bitmap: " + mName + " (activity running? "
+ mIsRunning + ")");
finish();
}
}
}
/**
* A class to encapsulate information about a theme.
*/
static class Theme {
public final int id;
public final int apiLevel;
public final String name;
private Theme(int id, int apiLevel, String name) {
this.id = id;
this.apiLevel = apiLevel;
this.name = name;
}
}
// List of themes to verify.
static final Theme[] THEMES = {
// Holo
new Theme(android.R.style.Theme_Holo,
Build.VERSION_CODES.HONEYCOMB, "holo"),
new Theme(android.R.style.Theme_Holo_Dialog,
Build.VERSION_CODES.HONEYCOMB, "holo_dialog"),
new Theme(android.R.style.Theme_Holo_Dialog_MinWidth,
Build.VERSION_CODES.HONEYCOMB, "holo_dialog_minwidth"),
new Theme(android.R.style.Theme_Holo_Dialog_NoActionBar,
Build.VERSION_CODES.HONEYCOMB, "holo_dialog_noactionbar"),
new Theme(android.R.style.Theme_Holo_Dialog_NoActionBar_MinWidth,
Build.VERSION_CODES.HONEYCOMB, "holo_dialog_noactionbar_minwidth"),
new Theme(android.R.style.Theme_Holo_DialogWhenLarge,
Build.VERSION_CODES.HONEYCOMB, "holo_dialogwhenlarge"),
new Theme(android.R.style.Theme_Holo_DialogWhenLarge_NoActionBar,
Build.VERSION_CODES.HONEYCOMB, "holo_dialogwhenlarge_noactionbar"),
new Theme(android.R.style.Theme_Holo_InputMethod,
Build.VERSION_CODES.HONEYCOMB, "holo_inputmethod"),
new Theme(android.R.style.Theme_Holo_NoActionBar,
Build.VERSION_CODES.HONEYCOMB, "holo_noactionbar"),
new Theme(android.R.style.Theme_Holo_NoActionBar_Fullscreen,
Build.VERSION_CODES.HONEYCOMB, "holo_noactionbar_fullscreen"),
new Theme(android.R.style.Theme_Holo_NoActionBar_Overscan,
Build.VERSION_CODES.JELLY_BEAN_MR2, "holo_noactionbar_overscan"),
new Theme(android.R.style.Theme_Holo_NoActionBar_TranslucentDecor,
Build.VERSION_CODES.KITKAT, "holo_noactionbar_translucentdecor"),
new Theme(android.R.style.Theme_Holo_Panel,
Build.VERSION_CODES.HONEYCOMB, "holo_panel"),
new Theme(android.R.style.Theme_Holo_Wallpaper,
Build.VERSION_CODES.HONEYCOMB, "holo_wallpaper"),
new Theme(android.R.style.Theme_Holo_Wallpaper_NoTitleBar,
Build.VERSION_CODES.HONEYCOMB, "holo_wallpaper_notitlebar"),
// Holo Light
new Theme(android.R.style.Theme_Holo_Light,
Build.VERSION_CODES.HONEYCOMB, "holo_light"),
new Theme(android.R.style.Theme_Holo_Light_DarkActionBar,
Build.VERSION_CODES.ICE_CREAM_SANDWICH, "holo_light_darkactionbar"),
new Theme(android.R.style.Theme_Holo_Light_Dialog,
Build.VERSION_CODES.HONEYCOMB, "holo_light_dialog"),
new Theme(android.R.style.Theme_Holo_Light_Dialog_MinWidth,
Build.VERSION_CODES.HONEYCOMB, "holo_light_dialog_minwidth"),
new Theme(android.R.style.Theme_Holo_Light_Dialog_NoActionBar,
Build.VERSION_CODES.HONEYCOMB, "holo_light_dialog_noactionbar"),
new Theme(android.R.style.Theme_Holo_Light_Dialog_NoActionBar_MinWidth,
Build.VERSION_CODES.HONEYCOMB, "holo_light_dialog_noactionbar_minwidth"),
new Theme(android.R.style.Theme_Holo_Light_DialogWhenLarge,
Build.VERSION_CODES.HONEYCOMB, "holo_light_dialogwhenlarge"),
new Theme(android.R.style.Theme_Holo_Light_DialogWhenLarge_NoActionBar,
Build.VERSION_CODES.HONEYCOMB, "holo_light_dialogwhenlarge_noactionbar"),
new Theme(android.R.style.Theme_Holo_Light_NoActionBar,
Build.VERSION_CODES.HONEYCOMB_MR2, "holo_light_noactionbar"),
new Theme(android.R.style.Theme_Holo_Light_NoActionBar_Fullscreen,
Build.VERSION_CODES.HONEYCOMB_MR2, "holo_light_noactionbar_fullscreen"),
new Theme(android.R.style.Theme_Holo_Light_NoActionBar_Overscan,
Build.VERSION_CODES.JELLY_BEAN_MR2, "holo_light_noactionbar_overscan"),
new Theme(android.R.style.Theme_Holo_Light_NoActionBar_TranslucentDecor,
Build.VERSION_CODES.KITKAT, "holo_light_noactionbar_translucentdecor"),
new Theme(android.R.style.Theme_Holo_Light_Panel,
Build.VERSION_CODES.HONEYCOMB, "holo_light_panel"),
// Material
new Theme(android.R.style.Theme_Material,
Build.VERSION_CODES.LOLLIPOP, "material"),
new Theme(android.R.style.Theme_Material_Dialog,
Build.VERSION_CODES.LOLLIPOP, "material_dialog"),
new Theme(android.R.style.Theme_Material_Dialog_Alert,
Build.VERSION_CODES.LOLLIPOP, "material_dialog_alert"),
new Theme(android.R.style.Theme_Material_Dialog_MinWidth,
Build.VERSION_CODES.LOLLIPOP, "material_dialog_minwidth"),
new Theme(android.R.style.Theme_Material_Dialog_NoActionBar,
Build.VERSION_CODES.LOLLIPOP, "material_dialog_noactionbar"),
new Theme(android.R.style.Theme_Material_Dialog_NoActionBar_MinWidth,
Build.VERSION_CODES.LOLLIPOP, "material_dialog_noactionbar_minwidth"),
new Theme(android.R.style.Theme_Material_Dialog_Presentation,
Build.VERSION_CODES.LOLLIPOP, "material_dialog_presentation"),
new Theme(android.R.style.Theme_Material_DialogWhenLarge,
Build.VERSION_CODES.LOLLIPOP, "material_dialogwhenlarge"),
new Theme(android.R.style.Theme_Material_DialogWhenLarge_NoActionBar,
Build.VERSION_CODES.LOLLIPOP, "material_dialogwhenlarge_noactionbar"),
new Theme(android.R.style.Theme_Material_InputMethod,
Build.VERSION_CODES.LOLLIPOP, "material_inputmethod"),
new Theme(android.R.style.Theme_Material_NoActionBar,
Build.VERSION_CODES.LOLLIPOP, "material_noactionbar"),
new Theme(android.R.style.Theme_Material_NoActionBar_Fullscreen,
Build.VERSION_CODES.LOLLIPOP, "material_noactionbar_fullscreen"),
new Theme(android.R.style.Theme_Material_NoActionBar_Overscan,
Build.VERSION_CODES.LOLLIPOP, "material_noactionbar_overscan"),
new Theme(android.R.style.Theme_Material_NoActionBar_TranslucentDecor,
Build.VERSION_CODES.LOLLIPOP, "material_noactionbar_translucentdecor"),
new Theme(android.R.style.Theme_Material_Panel,
Build.VERSION_CODES.LOLLIPOP, "material_panel"),
new Theme(android.R.style.Theme_Material_Settings,
Build.VERSION_CODES.LOLLIPOP, "material_settings"),
new Theme(android.R.style.Theme_Material_Voice,
Build.VERSION_CODES.LOLLIPOP, "material_voice"),
new Theme(android.R.style.Theme_Material_Wallpaper,
Build.VERSION_CODES.LOLLIPOP, "material_wallpaper"),
new Theme(android.R.style.Theme_Material_Wallpaper_NoTitleBar,
Build.VERSION_CODES.LOLLIPOP, "material_wallpaper_notitlebar"),
// Material Light
new Theme(android.R.style.Theme_Material_Light,
Build.VERSION_CODES.LOLLIPOP, "material_light"),
new Theme(android.R.style.Theme_Material_Light_DarkActionBar,
Build.VERSION_CODES.LOLLIPOP, "material_light_darkactionbar"),
new Theme(android.R.style.Theme_Material_Light_Dialog,
Build.VERSION_CODES.LOLLIPOP, "material_light_dialog"),
new Theme(android.R.style.Theme_Material_Light_Dialog_Alert,
Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_alert"),
new Theme(android.R.style.Theme_Material_Light_Dialog_MinWidth,
Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_minwidth"),
new Theme(android.R.style.Theme_Material_Light_Dialog_NoActionBar,
Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_noactionbar"),
new Theme(android.R.style.Theme_Material_Light_Dialog_NoActionBar_MinWidth,
Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_noactionbar_minwidth"),
new Theme(android.R.style.Theme_Material_Light_Dialog_Presentation,
Build.VERSION_CODES.LOLLIPOP, "material_light_dialog_presentation"),
new Theme(android.R.style.Theme_Material_Light_DialogWhenLarge,
Build.VERSION_CODES.LOLLIPOP, "material_light_dialogwhenlarge"),
new Theme(android.R.style.Theme_Material_Light_DialogWhenLarge_NoActionBar,
Build.VERSION_CODES.LOLLIPOP, "material_light_dialogwhenlarge_noactionbar"),
new Theme(android.R.style.Theme_Material_Light_LightStatusBar,
Build.VERSION_CODES.M, "material_light_lightstatusbar"),
new Theme(android.R.style.Theme_Material_Light_NoActionBar,
Build.VERSION_CODES.LOLLIPOP, "material_light_noactionbar"),
new Theme(android.R.style.Theme_Material_Light_NoActionBar_Fullscreen,
Build.VERSION_CODES.LOLLIPOP, "material_light_noactionbar_fullscreen"),
new Theme(android.R.style.Theme_Material_Light_NoActionBar_Overscan,
Build.VERSION_CODES.LOLLIPOP, "material_light_noactionbar_overscan"),
new Theme(android.R.style.Theme_Material_Light_NoActionBar_TranslucentDecor,
Build.VERSION_CODES.LOLLIPOP, "material_light_noactionbar_translucentdecor"),
new Theme(android.R.style.Theme_Material_Light_Panel,
Build.VERSION_CODES.LOLLIPOP, "material_light_panel"),
new Theme(android.R.style.Theme_Material_Light_Voice,
Build.VERSION_CODES.LOLLIPOP, "material_light_voice")
};
/**
* A class to encapsulate information about a layout.
*/
private static class Layout {
public final int id;
public final String name;
public final LayoutModifier modifier;
private Layout(int id, String name) {
this(id, name, null);
}
private Layout(int id, String name, LayoutModifier modifier) {
this.id = id;
this.name = name;
this.modifier = modifier;
}
}
// List of layouts to verify for each theme.
private static final Layout[] LAYOUTS = {
new Layout(R.layout.button, "button"),
new Layout(R.layout.button, "button_pressed",
new ViewPressedModifier()),
new Layout(R.layout.checkbox, "checkbox"),
new Layout(R.layout.checkbox, "checkbox_checked",
new ViewCheckedModifier()),
new Layout(R.layout.chronometer, "chronometer"),
new Layout(R.layout.color_blue_bright, "color_blue_bright"),
new Layout(R.layout.color_blue_dark, "color_blue_dark"),
new Layout(R.layout.color_blue_light, "color_blue_light"),
new Layout(R.layout.color_green_dark, "color_green_dark"),
new Layout(R.layout.color_green_light, "color_green_light"),
new Layout(R.layout.color_orange_dark, "color_orange_dark"),
new Layout(R.layout.color_orange_light, "color_orange_light"),
new Layout(R.layout.color_purple, "color_purple"),
new Layout(R.layout.color_red_dark, "color_red_dark"),
new Layout(R.layout.color_red_light, "color_red_light"),
new Layout(R.layout.datepicker, "datepicker",
new DatePickerModifier()),
new Layout(R.layout.display_info, "display_info"),
new Layout(R.layout.edittext, "edittext"),
new Layout(R.layout.progressbar_horizontal_0, "progressbar_horizontal_0"),
new Layout(R.layout.progressbar_horizontal_100, "progressbar_horizontal_100"),
new Layout(R.layout.progressbar_horizontal_50, "progressbar_horizontal_50"),
new Layout(R.layout.progressbar_large, "progressbar_large",
new ProgressBarModifier()),
new Layout(R.layout.progressbar_small, "progressbar_small",
new ProgressBarModifier()),
new Layout(R.layout.progressbar, "progressbar",
new ProgressBarModifier()),
new Layout(R.layout.radiobutton_checked, "radiobutton_checked"),
new Layout(R.layout.radiobutton, "radiobutton"),
new Layout(R.layout.radiogroup_horizontal, "radiogroup_horizontal"),
new Layout(R.layout.radiogroup_vertical, "radiogroup_vertical"),
new Layout(R.layout.ratingbar_0, "ratingbar_0"),
new Layout(R.layout.ratingbar_2point5, "ratingbar_2point5"),
new Layout(R.layout.ratingbar_5, "ratingbar_5"),
new Layout(R.layout.ratingbar_0, "ratingbar_0_pressed",
new ViewPressedModifier()),
new Layout(R.layout.ratingbar_2point5, "ratingbar_2point5_pressed",
new ViewPressedModifier()),
new Layout(R.layout.ratingbar_5, "ratingbar_5_pressed",
new ViewPressedModifier()),
new Layout(R.layout.searchview, "searchview_query",
new SearchViewModifier(SearchViewModifier.QUERY)),
new Layout(R.layout.searchview, "searchview_query_hint",
new SearchViewModifier(SearchViewModifier.QUERY_HINT)),
new Layout(R.layout.seekbar_0, "seekbar_0"),
new Layout(R.layout.seekbar_100, "seekbar_100"),
new Layout(R.layout.seekbar_50, "seekbar_50"),
new Layout(R.layout.spinner, "spinner"),
new Layout(R.layout.switch_button_checked, "switch_button_checked"),
new Layout(R.layout.switch_button, "switch_button"),
new Layout(R.layout.textview, "textview"),
new Layout(R.layout.timepicker, "timepicker",
new TimePickerModifier()),
new Layout(R.layout.togglebutton_checked, "togglebutton_checked"),
new Layout(R.layout.togglebutton, "togglebutton"),
new Layout(R.layout.zoomcontrols, "zoomcontrols"),
};
}