Initial import of Theme Verification Test.

Most of what is left is writing more individual tests.
The framework itself is pretty much there at this point.

Change-Id: I838d90529212e6a1741dc5dc70f0d6ea505e637a
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index 0a9c79e..ecf595a 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -59,6 +59,7 @@
 	CtsTelephonyTestCases \
 	CtsTestStubs \
 	CtsTextTestCases \
+	CtsThemeTestCases \
 	CtsUtilTestCases \
 	CtsViewTestCases \
 	CtsWebkitTestCases \
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 2d95899..c7e39dd 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -960,6 +960,25 @@
             </intent-filter>
         </service>
 
+        <activity android:name="android.theme.cts.ThemeTestRunnerActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
+        <activity android:name="android.theme.cts.ThemeTestGeneratorActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
+        <activity android:name="android.theme.cts.HomeActivity"
+                  android:theme="@android:style/Theme.Holo">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
     </application>
 
     <!--Test for PackageManager, please put this at the very beginning-->
diff --git a/tests/res/drawable-hdpi/holo_button.png b/tests/res/drawable-hdpi/holo_button.png
new file mode 100644
index 0000000..6c99b45
--- /dev/null
+++ b/tests/res/drawable-hdpi/holo_button.png
Binary files differ
diff --git a/tests/res/drawable-hdpi/holo_button_pressed.png b/tests/res/drawable-hdpi/holo_button_pressed.png
new file mode 100644
index 0000000..e85707d
--- /dev/null
+++ b/tests/res/drawable-hdpi/holo_button_pressed.png
Binary files differ
diff --git a/tests/res/drawable-hdpi/holo_light_button.png b/tests/res/drawable-hdpi/holo_light_button.png
new file mode 100644
index 0000000..97ca453
--- /dev/null
+++ b/tests/res/drawable-hdpi/holo_light_button.png
Binary files differ
diff --git a/tests/res/drawable-hdpi/holo_light_button_pressed.png b/tests/res/drawable-hdpi/holo_light_button_pressed.png
new file mode 100644
index 0000000..f8ebec2
--- /dev/null
+++ b/tests/res/drawable-hdpi/holo_light_button_pressed.png
Binary files differ
diff --git a/tests/res/layout/button.xml b/tests/res/layout/button.xml
new file mode 100644
index 0000000..ea0aec9
--- /dev/null
+++ b/tests/res/layout/button.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+    <Button xmlns:android="http://schemas.android.com/apk/res/android"
+            android:text="@string/button"
+            android:id="@+id/button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content">
+    </Button>
diff --git a/tests/res/layout/home_activity.xml b/tests/res/layout/home_activity.xml
new file mode 100644
index 0000000..49174da
--- /dev/null
+++ b/tests/res/layout/home_activity.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+      <Button android:text="@string/holo_test"
+              android:id="@+id/button_holo"
+              android:onClick="onHoloTestClick"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content">
+      </Button>
+      <Button android:text="@string/holo_generator"
+              android:id="@+id/button2"
+              android:onClick="onHoloGenClick"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content">
+      </Button>
+      <Button android:text="@string/holo_light_test"
+              android:id="@+id/button3"
+              android:onClick="onHoloLightTestClick"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content">
+      </Button>
+      <Button android:text="@string/holo_light_generator"
+              android:id="@+id/button4"
+              android:onClick="onHoloLightGenClick"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content">
+      </Button>
+</LinearLayout>
diff --git a/tests/res/layout/testing_activity.xml b/tests/res/layout/testing_activity.xml
new file mode 100644
index 0000000..8b9a47a
--- /dev/null
+++ b/tests/res/layout/testing_activity.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+    <TextView android:id="@+id/text"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content">
+    </TextView>
+    <TextView android:id="@+id/text_reference"
+              android:text="@string/reference_image"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:layout_below="@+id/text">
+    </TextView>
+    <ImageView android:id="@+id/reference_image"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:layout_toRightOf="@+id/text_reference"
+               android:layout_below="@+id/text"/>
+    <TextView android:id="@+id/text_generated"
+              android:text="@string/generated_image"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:layout_toLeftOf="@+id/generated_image"
+              android:layout_alignTop="@+id/generated_image">
+    </TextView>
+    <ImageView android:id="@+id/generated_image"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:layout_below="@+id/reference_image"
+               android:layout_alignLeft="@+id/reference_image"/>
+    <android.theme.cts.TesterViewGroup android:id="@+id/test_group"
+                                       android:layout_width="wrap_content"
+                                       android:layout_height="wrap_content"
+                                       android:layout_below="@+id/generated_image"/>
+</RelativeLayout>
diff --git a/tests/res/values/dimens.xml b/tests/res/values/dimens.xml
index 2a8f76e..f0c57c2 100755
--- a/tests/res/values/dimens.xml
+++ b/tests/res/values/dimens.xml
@@ -38,6 +38,9 @@
     <item name="frac25510pperc" type="dimen" format="fraction">25510%p</item>
     <item name="frac25610pperc" type="dimen" format="fraction">25610%p</item>
     <item name="frac6553510pperc" type="dimen" format="fraction">6553510%p</item>
-    <item name="frac6553610pperc" type="dimen" format="fraction">6553610%p</item> 
+    <item name="frac6553610pperc" type="dimen" format="fraction">6553610%p</item>
+
+    <dimen name="reference_width">320dp</dimen>
+    <dimen name="reference_height">480dp</dimen>
 </resources>
 
diff --git a/tests/res/values/strings.xml b/tests/res/values/strings.xml
index 8fcd75a..27ef32f 100644
--- a/tests/res/values/strings.xml
+++ b/tests/res/values/strings.xml
@@ -151,4 +151,13 @@
    <string name="version_v3">base</string>
    <string name="authenticator_label">Android CTS</string>
    <string name="search_label">Android CTS</string>
+
+
+   <string name="button">Button</string>
+   <string name="holo_test">Holo Test</string>
+   <string name="holo_generator">Holo Generator</string>
+   <string name="holo_light_test">Holo Light Test</string>
+   <string name="holo_light_generator">Holo Light Generator</string>
+   <string name="reference_image">Reference Image: </string>
+   <string name="generated_image">Generated Image: </string>
 </resources>
diff --git a/tests/src/android/theme/cts/HomeActivity.java b/tests/src/android/theme/cts/HomeActivity.java
new file mode 100644
index 0000000..04b75a1
--- /dev/null
+++ b/tests/src/android/theme/cts/HomeActivity.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2011 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.stub.R;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+
+/**
+ * This activity exists solely for debugging purposes.
+ */
+public class HomeActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.home_activity);
+    }
+
+    public void onHoloTestClick(View view) {
+        Intent intent = new Intent(this, ThemeTestRunnerActivity.class);
+        intent.putExtra(ThemeTests.EXTRA_THEME_ID, android.R.style.Theme_Holo);
+        intent.putExtra(ThemeTests.EXTRA_THEME_NAME, "holo");
+        intent.putExtra(ThemeTests.EXTRA_RUN_TESTS, true);
+        startActivity(intent);
+    }
+
+    public void onHoloGenClick(View view) {
+        Intent intent = new Intent(this, ThemeTestGeneratorActivity.class);
+        intent.putExtra(ThemeTests.EXTRA_THEME_ID, android.R.style.Theme_Holo);
+        intent.putExtra(ThemeTests.EXTRA_THEME_NAME, "holo");
+        startActivity(intent);
+    }
+
+    public void onHoloLightTestClick(View view) {
+        Intent intent = new Intent(this, ThemeTestRunnerActivity.class);
+        intent.putExtra(ThemeTests.EXTRA_THEME_ID, android.R.style.Theme_Holo_Light);
+        intent.putExtra(ThemeTests.EXTRA_THEME_NAME, "holo_light");
+        intent.putExtra(ThemeTests.EXTRA_RUN_TESTS, true);
+        startActivity(intent);
+    }
+
+    public void onHoloLightGenClick(View view) {
+        Intent intent = new Intent(this, ThemeTestGeneratorActivity.class);
+        intent.putExtra(ThemeTests.EXTRA_THEME_ID, android.R.style.Theme_Holo_Light);
+        intent.putExtra(ThemeTests.EXTRA_THEME_NAME, "holo_light");
+        startActivity(intent);
+    }
+}
diff --git a/tests/src/android/theme/cts/TesterViewGroup.java b/tests/src/android/theme/cts/TesterViewGroup.java
new file mode 100644
index 0000000..f8f9b8f
--- /dev/null
+++ b/tests/src/android/theme/cts/TesterViewGroup.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2011 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.stub.R;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Custom view group to handle density changes while maintaining screen independence.
+ */
+public class TesterViewGroup extends ViewGroup {
+    private int mReferenceWidthDp;
+    private int mReferenceHeightDp;
+
+    public TesterViewGroup(Context context) {
+        this(context, null);
+    }
+
+    public TesterViewGroup(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        Resources resources = context.getResources();
+
+        mReferenceWidthDp = resources.getDimensionPixelSize(R.dimen.reference_width);
+        mReferenceHeightDp = resources.getDimensionPixelSize(R.dimen.reference_height);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        if (!changed) {
+            return;
+        }
+
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = getChildAt(i);
+            child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        widthMeasureSpec = getMeasureSpec(LayoutParams.MATCH_PARENT, mReferenceWidthDp);
+        heightMeasureSpec = getMeasureSpec(LayoutParams.MATCH_PARENT, mReferenceHeightDp);
+
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = getChildAt(i);
+
+            LayoutParams params = child.getLayoutParams();
+
+            int height = getMeasureSpec(params.height, mReferenceWidthDp);
+            int width = getMeasureSpec(params.width, mReferenceHeightDp);
+            child.measure(width, height);
+        }
+    }
+
+    private int getMeasureSpec(int val, int referenceSize) {
+        if (val == LayoutParams.MATCH_PARENT || val == LayoutParams.FILL_PARENT) {
+            return MeasureSpec.makeMeasureSpec(referenceSize, MeasureSpec.EXACTLY);
+        } else if (val == LayoutParams.WRAP_CONTENT) {
+            return MeasureSpec.makeMeasureSpec(referenceSize, MeasureSpec.AT_MOST);
+        } else {
+            return val;
+        }
+    }
+}
diff --git a/tests/src/android/theme/cts/ThemeTestGeneratorActivity.java b/tests/src/android/theme/cts/ThemeTestGeneratorActivity.java
new file mode 100644
index 0000000..37c8091
--- /dev/null
+++ b/tests/src/android/theme/cts/ThemeTestGeneratorActivity.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2011 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.stub.R;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+import junit.framework.Assert;
+
+public class ThemeTestGeneratorActivity extends Activity {
+
+    /**
+     * Called with the activity is first created.
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        Intent intent = getIntent();
+        int themeId = intent.getIntExtra(ThemeTests.EXTRA_THEME_ID, 0);
+
+        // test should fail if no theme is set
+        Assert.assertTrue("No Theme Resource ID set", themeId != 0);
+
+        String themeName = intent.getStringExtra(ThemeTests.EXTRA_THEME_NAME);
+
+        setTheme(themeId);
+        setContentView(R.layout.testing_activity);
+
+        ThemeTester tester = new ThemeTester(this, themeName);
+        tester.generateTests();
+    }
+}
diff --git a/tests/src/android/theme/cts/ThemeTestInfo.java b/tests/src/android/theme/cts/ThemeTestInfo.java
new file mode 100644
index 0000000..c629f43
--- /dev/null
+++ b/tests/src/android/theme/cts/ThemeTestInfo.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2011 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;
+
+/**
+ * Class that represents a test case. Add a new one to the list of tests in ThemeTests.java
+ * in order to create a new test.
+ */
+public class ThemeTestInfo {
+    private int mResourceId;
+    private ThemeTestModifier mModifier;
+    private String mFilename;
+
+    /**
+     * Creates a new theme test.
+     * @param layoutResourceId The resource ID of the layout to use for this test.
+     * @param modifier The {@link ThemeTestModifier} to use in order to modify the layout
+     * of the test.
+     * @param testname The UNIQUE name of the test.
+     */
+    public ThemeTestInfo(int layoutResourceId, ThemeTestModifier modifier, String testname) {
+        mResourceId = layoutResourceId;
+        mModifier = modifier;
+        mFilename = testname;
+    }
+
+    public int getLayoutResourceId() {
+        return mResourceId;
+    }
+
+    public ThemeTestModifier getThemeModifier() {
+        return mModifier;
+    }
+
+    public String getTestName() {
+        return mFilename;
+    }
+}
diff --git a/tests/src/android/theme/cts/ThemeTestModifier.java b/tests/src/android/theme/cts/ThemeTestModifier.java
new file mode 100644
index 0000000..436b2e2
--- /dev/null
+++ b/tests/src/android/theme/cts/ThemeTestModifier.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011 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 android.view.View;
+
+/**
+ * Interface that should be implemented if you want to modify the view being tested.
+ *
+ * For a sample implementation, see {@link ViewPressedModifier}.
+ */
+public interface ThemeTestModifier {
+    /**
+     * Define this function in order to modify the layout for your test.
+     * The View that is passed in is the root of layout that is specified in the test.
+     * @param view The root view of the layout.
+     */
+    public void modifyView(View view);
+}
diff --git a/tests/src/android/theme/cts/ThemeTestRunnerActivity.java b/tests/src/android/theme/cts/ThemeTestRunnerActivity.java
new file mode 100644
index 0000000..631c5bc
--- /dev/null
+++ b/tests/src/android/theme/cts/ThemeTestRunnerActivity.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2011 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.stub.R;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+import junit.framework.Assert;
+
+public class ThemeTestRunnerActivity extends Activity {
+    private ThemeTester mTester;
+    /**
+     * Called with the activity is first created.
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        Intent intent = getIntent();
+        int themeId = intent.getIntExtra(ThemeTests.EXTRA_THEME_ID, 0);
+
+        // test should fail if no theme is set
+        Assert.assertTrue("No Theme Resource ID set", themeId != 0);
+
+        String themeName = intent.getStringExtra(ThemeTests.EXTRA_THEME_NAME);
+
+        setTheme(themeId);
+        setContentView(R.layout.testing_activity);
+
+        mTester = new ThemeTester(this, themeName);
+
+        if (intent.getBooleanExtra(ThemeTests.EXTRA_RUN_TESTS, false)) {
+            mTester.runTests();
+        }
+    }
+
+    /**
+     * Runs the theme tests for the theme that was created.
+     */
+    public void runTests() {
+        mTester.runTests();
+    }
+}
diff --git a/tests/src/android/theme/cts/ThemeTester.java b/tests/src/android/theme/cts/ThemeTester.java
new file mode 100644
index 0000000..c6be2d7
--- /dev/null
+++ b/tests/src/android/theme/cts/ThemeTester.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2011 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.stub.R;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import junit.framework.Assert;
+
+/**
+ * This class runs the series of tests for a specific theme in the activity.
+ *
+ * <p>
+ * Additionally, this class can also generate the good versions of bitmaps to use for testing.
+ */
+public class ThemeTester {
+    private Activity mActivity;
+    private String mThemeName;
+    private ImageView mReferenceImage;
+    private ImageView mGeneratedImage;
+    private TextView mText;
+    private TesterViewGroup mRoot;
+
+    /**
+     * Creates a ThemeTester to run all of the tests.
+     * @param activity Activity that serves as a test harness for this theme test.
+     * @param themeName Name of the theme being tested.
+     */
+    public ThemeTester(Activity activity, String themeName) {
+        mActivity = activity;
+        mThemeName = themeName;
+        mRoot = (TesterViewGroup) mActivity.findViewById(R.id.test_group);
+
+        // TODO - remove views that exist for debugging only
+        mReferenceImage = (ImageView) mActivity.findViewById(R.id.reference_image);
+        mGeneratedImage = (ImageView) mActivity.findViewById(R.id.generated_image);
+        mText = (TextView) mActivity.findViewById(R.id.text);
+    }
+
+    /**
+     * Run all of the tests.
+     */
+    public void runTests() {
+        ThemeTestInfo[] tests = ThemeTests.getTests();
+        for (final ThemeTestInfo test : tests) {
+            mText.post(new Runnable() {
+                public void run() {
+                    testViewFromId(test);
+                }
+            });
+        }
+    }
+
+    /**
+     * Generate all of the tests, saving them to Bitmaps in the application's data folder.
+     */
+    public void generateTests() {
+        ThemeTestInfo[] tests = ThemeTests.getTests();
+        for (final ThemeTestInfo test : tests) {
+            mText.post(new Runnable() {
+                public void run() {
+                    mText.setText("Bitmaps saved");
+                    generateViewFromId(test);
+                }
+            });
+        }
+    }
+
+    private void testViewFromId(ThemeTestInfo test) {
+        processBitmapFromViewId(test.getLayoutResourceId(), test.getThemeModifier(),
+                new BitmapComparer(mThemeName + "_" + test.getTestName()));
+    }
+
+    private void generateViewFromId(ThemeTestInfo test) {
+        processBitmapFromViewId(test.getLayoutResourceId(), test.getThemeModifier(),
+                new BitmapGenerator(mThemeName + "_" + test.getTestName()));
+    }
+
+    private void processBitmapFromViewId(
+            int resid, ThemeTestModifier modifier, final BitmapProcessor processor) {
+        final View view = constructViewFromLayoutId(resid, modifier);
+
+        view.post(new Runnable() {
+            public void run() {
+                Bitmap bitmap = Bitmap.createBitmap(
+                        view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
+
+                Canvas canvas = new Canvas(bitmap);
+                view.draw(canvas);
+                mGeneratedImage.setImageBitmap(bitmap);
+
+                if (processor.processBitmap(bitmap)) {
+                    mText.setText(mText.getText() + "\nBitmaps identical");
+                } else {
+                    mText.setText(mText.getText() + "\nBitmaps differ");
+                }
+
+                mRoot.removeView(view);
+            }
+        });
+    }
+
+    /**
+     * Inflates and returns the view and performs and modifications of it as required by the test.
+     * @param resid The resource id of the layout that will be constructed.
+     * @param modifier The ThemeTestModifier to modify the layout being tested.
+     * @return The root view of the layout being tested.
+     */
+    private View constructViewFromLayoutId(int resid, ThemeTestModifier modifier) {
+        LayoutInflater inflater = LayoutInflater.from(mActivity);
+
+        View view = inflater.inflate(resid, mRoot, false);
+        mRoot.addView(view);
+
+        mRoot.measure(0, 0); // don't care about the first two values - we build our reference size
+        mRoot.layout(0, 0, mRoot.getMeasuredWidth(), mRoot.getMeasuredHeight());
+
+        if (modifier != null) {
+            modifier.modifyView(view);
+        }
+
+        return view;
+    }
+
+    /**
+     * Simple interface in order to share code between the bitmap comparison and bitmap generation
+     * steps.
+     */
+    private interface BitmapProcessor {
+        public boolean processBitmap(Bitmap bitmap);
+    }
+
+    /**
+     * Implementation of {@link BitmapProcessor} that compares the created bitmap
+     * to a known good version. Asserts if the bitmaps do not compare.
+     */
+    private class BitmapComparer implements BitmapProcessor {
+        String mBitmapIdName;
+
+        public BitmapComparer(String filename) {
+            mBitmapIdName = filename;
+        }
+
+        @Override
+        public boolean processBitmap(Bitmap bitmap) {
+            Resources r = mActivity.getResources();
+            int resourceId = r.getIdentifier(mBitmapIdName, "drawable", mActivity.getPackageName());
+
+            BitmapDrawable drawable = (BitmapDrawable) r.getDrawable(resourceId);
+            Bitmap bmp2 = drawable.getBitmap();
+            mReferenceImage.setImageBitmap(bmp2);
+
+            Assert.assertTrue("Test failed: " + mBitmapIdName, bmp2.sameAs(bitmap));
+
+            return true;
+        }
+    }
+
+    /**
+     * Implementation of {@link BitmapProcessor} that creates a known-good version of the
+     * bitmap and saves it to the applications data folder.
+     */
+    private class BitmapGenerator implements BitmapProcessor {
+        String mFilename;
+
+        public BitmapGenerator(String filename) {
+            mFilename = filename + ".png";
+        }
+
+        @Override
+        public boolean processBitmap(Bitmap bitmap) {
+            try {
+                FileOutputStream fos = mActivity.openFileOutput(mFilename, Context.MODE_PRIVATE);
+                bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
+                fos.close();
+            } catch (FileNotFoundException e) {
+                // TODO - break loudly
+            } catch (IOException e) {
+                // TODO - break loudly
+            }
+
+            return false;
+        }
+
+    }
+}
diff --git a/tests/src/android/theme/cts/ThemeTests.java b/tests/src/android/theme/cts/ThemeTests.java
new file mode 100644
index 0000000..19db730
--- /dev/null
+++ b/tests/src/android/theme/cts/ThemeTests.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2011 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.stub.R;
+
+public class ThemeTests {
+    /**
+     * Theme name to test.
+     */
+    public static final String EXTRA_THEME_NAME = "android.intent.extra.THEME_NAME";
+
+    /**
+     * Theme ID to test.
+     */
+    public static final String EXTRA_THEME_ID = "android.intent.extra.THEME_ID";
+
+    /**
+     * Use solely for debugging. The actual intent that runs the tests will not have this flag.
+     */
+    public static final String EXTRA_RUN_TESTS = "android.intent.extra.RUN_TESTS";
+
+    /**
+     * The list of tests to run for each theme.<p>
+     *
+     * In order to create a new test, follow these steps.<p>
+     * 1. Create a layout file for the test you wish to run.<p>
+     * 2. (Optional) Create a class that derives from ThemeTestModifier
+     * that will modify the root view of your created layout. Set to null if you do not want
+     * to modify the view from the layout version.<p>
+     * 3. Create a unique String for the name of the test.<p>
+     * 4. Add all of the above to the list of tests. as a new {@link ThemeTestInfo}.
+     */
+    private static final ThemeTestInfo[] TESTS = new ThemeTestInfo[] {
+            new ThemeTestInfo(R.layout.button, null, "button"),
+            new ThemeTestInfo(R.layout.button, new ViewPressedModifier(), "button_pressed")};
+
+    /**
+     * Returns the list of tests to run on a particular theme.
+     *
+     * In order to create a new test, follow these steps.<p>
+     * 1. Create a layout file for the test you wish to run.<p>
+     * 2. (Optional) Create a class that derives from ThemeTestModifier
+     * that will modify the root view of your created layout. Set to null if you do not want
+     * to modify the view from the layout version.<p>
+     * 3. Create a unique String for the name of the test.<p>
+     * 4. Add all of the above to the list of tests. as a new {@link ThemeTestInfo}.
+     * @return The list of tests.
+     */
+    public static ThemeTestInfo[] getTests() {
+        return TESTS;
+    }
+}
diff --git a/tests/src/android/theme/cts/ViewPressedModifier.java b/tests/src/android/theme/cts/ViewPressedModifier.java
new file mode 100644
index 0000000..8a97c7f
--- /dev/null
+++ b/tests/src/android/theme/cts/ViewPressedModifier.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2011 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 android.view.View;
+
+/**
+ * Modifies the root view of a test so that it is in the pressed state.
+ */
+public class ViewPressedModifier implements ThemeTestModifier {
+
+    @Override
+    public void modifyView(View view) {
+        view.setPressed(true);
+    }
+
+}
diff --git a/tests/tests/theme/Android.mk b/tests/tests/theme/Android.mk
new file mode 100644
index 0000000..b28e6b3
--- /dev/null
+++ b/tests/tests/theme/Android.mk
@@ -0,0 +1,34 @@
+# Copyright (C) 2011 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+# and when built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsThemeTestCases
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_INSTRUMENTATION_FOR := CtsTestStubs
+
+include $(BUILD_PACKAGE)
diff --git a/tests/tests/theme/AndroidManifest.xml b/tests/tests/theme/AndroidManifest.xml
new file mode 100644
index 0000000..55afc7d
--- /dev/null
+++ b/tests/tests/theme/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.theme">
+
+    <!-- We add an application tag here just so that we can indicate that
+         this package needs to link against the android.test library,
+         which is needed when building test cases. -->
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+  <instrumentation android:name="android.test.InstrumentationCtsTestRunner"
+      android:targetPackage="com.android.cts.stub"
+      android:label="CTS tests for themes">
+  </instrumentation>
+
+</manifest>
diff --git a/tests/tests/theme/src/android/theme/cts/ThemeTest.java b/tests/tests/theme/src/android/theme/cts/ThemeTest.java
new file mode 100644
index 0000000..df00d7b
--- /dev/null
+++ b/tests/tests/theme/src/android/theme/cts/ThemeTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2011 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 android.app.Instrumentation;
+import android.content.Intent;
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+ * Make sure that the main launcher activity opens up properly, which will be
+ * verified by {@link #testActivityTestCaseSetUpProperly}.
+ */
+public class ThemeTest extends ActivityInstrumentationTestCase2<ThemeTestRunnerActivity> {
+    private Instrumentation mInstrumentation;
+
+    /**
+     * Creates an {@link ActivityInstrumentationTestCase2}
+     * for the {@link ThemeTestRunnerActivity} activity.
+     */
+    public ThemeTest() {
+        super(ThemeTestRunnerActivity.class);
+
+        mInstrumentation = getInstrumentation();
+    }
+
+    public void testHoloTheme() {
+        runThemeTest(android.R.style.Theme_Holo, "holo");
+    }
+
+    public void testHoloLightTheme() {
+        runThemeTest(android.R.style.Theme_Holo_Light, "holo_light");
+    }
+
+    /**
+     * Runs the theme test given the appropriate theme resource id and theme name.
+     * @param resourceId Resource ID of the theme being tested.
+     * @param themeName Name of the theme being tested, e.g., "holo", "holo_light", etc
+     */
+    private void runThemeTest(int resourceId, String themeName) {
+        if (mInstrumentation == null) {
+            mInstrumentation = getInstrumentation();
+        }
+
+        Intent intent = new Intent();
+        intent.putExtra(ThemeTests.EXTRA_THEME_ID, resourceId);
+        intent.putExtra(ThemeTests.EXTRA_THEME_NAME, themeName);
+        setActivityIntent(intent);
+
+        final ThemeTestRunnerActivity activity = getActivity();
+
+        activity.runOnUiThread(new Runnable() {
+           public void run() {
+               activity.runTests();
+           }
+        });
+
+        mInstrumentation.waitForIdleSync();
+    }
+}