Merge "Runtime resource overlay, iteration 2, test cases"
diff --git a/core/tests/overlaytests/OverlayAppFirst/Android.mk b/core/tests/overlaytests/OverlayAppFirst/Android.mk
new file mode 100644
index 0000000..ee991fc
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppFirst/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := com.android.overlaytest.first_app_overlay
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/OverlayAppFirst/AndroidManifest.xml b/core/tests/overlaytests/OverlayAppFirst/AndroidManifest.xml
new file mode 100644
index 0000000..ec10bbc
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppFirst/AndroidManifest.xml
@@ -0,0 +1,6 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.overlaytest.first_app_overlay"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay android:targetPackage="com.android.overlaytest" android:priority="1"/>
+</manifest>
diff --git a/core/tests/overlaytests/OverlayTestOverlay/res/drawable-nodpi/default_wallpaper.jpg b/core/tests/overlaytests/OverlayAppFirst/res/drawable-nodpi/drawable.jpg
similarity index 100%
rename from core/tests/overlaytests/OverlayTestOverlay/res/drawable-nodpi/default_wallpaper.jpg
rename to core/tests/overlaytests/OverlayAppFirst/res/drawable-nodpi/drawable.jpg
Binary files differ
diff --git a/core/tests/overlaytests/OverlayAppFirst/res/raw/lorem_ipsum.txt b/core/tests/overlaytests/OverlayAppFirst/res/raw/lorem_ipsum.txt
new file mode 100644
index 0000000..756b0a3
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppFirst/res/raw/lorem_ipsum.txt
@@ -0,0 +1 @@
+Lorem ipsum: single overlay.
diff --git a/core/tests/overlaytests/OverlayAppFirst/res/values-sv/config.xml b/core/tests/overlaytests/OverlayAppFirst/res/values-sv/config.xml
new file mode 100644
index 0000000..9cdc73e
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppFirst/res/values-sv/config.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <integer name="matrix_100100">400</integer>
+ <integer name="matrix_100101">400</integer>
+ <integer name="matrix_100110">400</integer>
+ <integer name="matrix_100111">400</integer>
+ <integer name="matrix_101100">400</integer>
+ <integer name="matrix_101101">400</integer>
+ <integer name="matrix_101110">400</integer>
+ <integer name="matrix_101111">400</integer>
+ <integer name="matrix_110100">400</integer>
+ <integer name="matrix_110101">400</integer>
+ <integer name="matrix_110110">400</integer>
+ <integer name="matrix_110111">400</integer>
+ <integer name="matrix_111100">400</integer>
+ <integer name="matrix_111101">400</integer>
+ <integer name="matrix_111110">400</integer>
+ <integer name="matrix_111111">400</integer>
+</resources>
diff --git a/core/tests/overlaytests/OverlayAppFirst/res/values/config.xml b/core/tests/overlaytests/OverlayAppFirst/res/values/config.xml
new file mode 100644
index 0000000..972137a
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppFirst/res/values/config.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="str">single</string>
+ <string name="str2">single</string>
+ <integer name="matrix_101000">300</integer>
+ <integer name="matrix_101001">300</integer>
+ <integer name="matrix_101010">300</integer>
+ <integer name="matrix_101011">300</integer>
+ <integer name="matrix_101100">300</integer>
+ <integer name="matrix_101101">300</integer>
+ <integer name="matrix_101110">300</integer>
+ <integer name="matrix_101111">300</integer>
+ <integer name="matrix_111000">300</integer>
+ <integer name="matrix_111001">300</integer>
+ <integer name="matrix_111010">300</integer>
+ <integer name="matrix_111011">300</integer>
+ <integer name="matrix_111100">300</integer>
+ <integer name="matrix_111101">300</integer>
+ <integer name="matrix_111110">300</integer>
+ <integer name="matrix_111111">300</integer>
+ <bool name="usually_false">true</bool>
+ <integer-array name="fibonacci">
+ <item>21</item>
+ <item>13</item>
+ <item>8</item>
+ <item>5</item>
+ <item>3</item>
+ <item>2</item>
+ <item>1</item>
+ <item>1</item>
+ </integer-array>
+ <!-- The following integer does not exist in the original package. Idmap
+ generation should therefore ignore it. -->
+ <integer name="integer_not_in_original_package">0</integer>
+</resources>
diff --git a/core/tests/overlaytests/OverlayAppFirst/res/xml/integer.xml b/core/tests/overlaytests/OverlayAppFirst/res/xml/integer.xml
new file mode 100644
index 0000000..7f628d9
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppFirst/res/xml/integer.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<integer value="1"/>
diff --git a/core/tests/overlaytests/OverlayAppSecond/Android.mk b/core/tests/overlaytests/OverlayAppSecond/Android.mk
new file mode 100644
index 0000000..87402c43
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppSecond/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := com.android.overlaytest.second_app_overlay
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/OverlayAppSecond/AndroidManifest.xml b/core/tests/overlaytests/OverlayAppSecond/AndroidManifest.xml
new file mode 100644
index 0000000..ed49863
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppSecond/AndroidManifest.xml
@@ -0,0 +1,6 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.overlaytest.second_app_overlay"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay android:targetPackage="com.android.overlaytest" android:priority="2"/>
+</manifest>
diff --git a/core/tests/overlaytests/OverlayAppSecond/res/raw/lorem_ipsum.txt b/core/tests/overlaytests/OverlayAppSecond/res/raw/lorem_ipsum.txt
new file mode 100644
index 0000000..613f5b6
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppSecond/res/raw/lorem_ipsum.txt
@@ -0,0 +1 @@
+Lorem ipsum: multiple overlays.
diff --git a/core/tests/overlaytests/OverlayAppSecond/res/values-sv/config.xml b/core/tests/overlaytests/OverlayAppSecond/res/values-sv/config.xml
new file mode 100644
index 0000000..ec4b6c0
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppSecond/res/values-sv/config.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <integer name="matrix_100001">600</integer>
+ <integer name="matrix_100011">600</integer>
+ <integer name="matrix_100101">600</integer>
+ <integer name="matrix_100111">600</integer>
+ <integer name="matrix_101001">600</integer>
+ <integer name="matrix_101011">600</integer>
+ <integer name="matrix_101101">600</integer>
+ <integer name="matrix_101111">600</integer>
+ <integer name="matrix_110001">600</integer>
+ <integer name="matrix_110011">600</integer>
+ <integer name="matrix_110101">600</integer>
+ <integer name="matrix_110111">600</integer>
+ <integer name="matrix_111001">600</integer>
+ <integer name="matrix_111011">600</integer>
+ <integer name="matrix_111101">600</integer>
+ <integer name="matrix_111111">600</integer>
+</resources>
diff --git a/core/tests/overlaytests/OverlayAppSecond/res/values/config.xml b/core/tests/overlaytests/OverlayAppSecond/res/values/config.xml
new file mode 100644
index 0000000..8b07216
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppSecond/res/values/config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="str">multiple</string>
+ <integer name="matrix_100010">500</integer>
+ <integer name="matrix_100011">500</integer>
+ <integer name="matrix_100110">500</integer>
+ <integer name="matrix_100111">500</integer>
+ <integer name="matrix_101010">500</integer>
+ <integer name="matrix_101011">500</integer>
+ <integer name="matrix_101110">500</integer>
+ <integer name="matrix_101111">500</integer>
+ <integer name="matrix_110010">500</integer>
+ <integer name="matrix_110011">500</integer>
+ <integer name="matrix_110110">500</integer>
+ <integer name="matrix_110111">500</integer>
+ <integer name="matrix_111010">500</integer>
+ <integer name="matrix_111011">500</integer>
+ <integer name="matrix_111110">500</integer>
+ <integer name="matrix_111111">500</integer>
+ <bool name="usually_false">false</bool>
+</resources>
diff --git a/core/tests/overlaytests/OverlayAppSecond/res/xml/integer.xml b/core/tests/overlaytests/OverlayAppSecond/res/xml/integer.xml
new file mode 100644
index 0000000..f3370a6
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppSecond/res/xml/integer.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<integer value="2"/>
diff --git a/core/tests/overlaytests/OverlayTest/Android.mk b/core/tests/overlaytests/OverlayTest/Android.mk
index f7f67f6..4767e52 100644
--- a/core/tests/overlaytests/OverlayTest/Android.mk
+++ b/core/tests/overlaytests/OverlayTest/Android.mk
@@ -5,6 +5,10 @@
LOCAL_PACKAGE_NAME := OverlayTest
+LOCAL_DEX_PREOPT := false
+
+LOCAL_MODULE_PATH := $(TARGET_OUT)/app
+
LOCAL_SRC_FILES := $(call all-java-files-under, src)
include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/OverlayTest/res/drawable-nodpi/drawable.jpg b/core/tests/overlaytests/OverlayTest/res/drawable-nodpi/drawable.jpg
new file mode 100644
index 0000000..a3f14f3
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/res/drawable-nodpi/drawable.jpg
Binary files differ
diff --git a/core/tests/overlaytests/OverlayTest/res/raw/lorem_ipsum.txt b/core/tests/overlaytests/OverlayTest/res/raw/lorem_ipsum.txt
new file mode 100644
index 0000000..cee7a92
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/res/raw/lorem_ipsum.txt
@@ -0,0 +1 @@
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
diff --git a/core/tests/overlaytests/OverlayTest/res/values-sv/config.xml b/core/tests/overlaytests/OverlayTest/res/values-sv/config.xml
new file mode 100644
index 0000000..891853e
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/res/values-sv/config.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <integer name="matrix_110000">200</integer>
+ <integer name="matrix_110001">200</integer>
+ <integer name="matrix_110010">200</integer>
+ <integer name="matrix_110011">200</integer>
+ <integer name="matrix_110100">200</integer>
+ <integer name="matrix_110101">200</integer>
+ <integer name="matrix_110110">200</integer>
+ <integer name="matrix_110111">200</integer>
+ <integer name="matrix_111000">200</integer>
+ <integer name="matrix_111001">200</integer>
+ <integer name="matrix_111010">200</integer>
+ <integer name="matrix_111011">200</integer>
+ <integer name="matrix_111100">200</integer>
+ <integer name="matrix_111101">200</integer>
+ <integer name="matrix_111110">200</integer>
+ <integer name="matrix_111111">200</integer>
+</resources>
diff --git a/core/tests/overlaytests/OverlayTest/res/values/config.xml b/core/tests/overlaytests/OverlayTest/res/values/config.xml
new file mode 100644
index 0000000..c692a262
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/res/values/config.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="str">none</string>
+ <string name="str2">none</string>
+ <integer name="matrix_100000">100</integer>
+ <integer name="matrix_100001">100</integer>
+ <integer name="matrix_100010">100</integer>
+ <integer name="matrix_100011">100</integer>
+ <integer name="matrix_100100">100</integer>
+ <integer name="matrix_100101">100</integer>
+ <integer name="matrix_100110">100</integer>
+ <integer name="matrix_100111">100</integer>
+ <integer name="matrix_101000">100</integer>
+ <integer name="matrix_101001">100</integer>
+ <integer name="matrix_101010">100</integer>
+ <integer name="matrix_101011">100</integer>
+ <integer name="matrix_101100">100</integer>
+ <integer name="matrix_101101">100</integer>
+ <integer name="matrix_101110">100</integer>
+ <integer name="matrix_101111">100</integer>
+ <integer name="matrix_110000">100</integer>
+ <integer name="matrix_110001">100</integer>
+ <integer name="matrix_110010">100</integer>
+ <integer name="matrix_110011">100</integer>
+ <integer name="matrix_110100">100</integer>
+ <integer name="matrix_110101">100</integer>
+ <integer name="matrix_110110">100</integer>
+ <integer name="matrix_110111">100</integer>
+ <integer name="matrix_111000">100</integer>
+ <integer name="matrix_111001">100</integer>
+ <integer name="matrix_111010">100</integer>
+ <integer name="matrix_111011">100</integer>
+ <integer name="matrix_111100">100</integer>
+ <integer name="matrix_111101">100</integer>
+ <integer name="matrix_111110">100</integer>
+ <integer name="matrix_111111">100</integer>
+ <bool name="usually_false">false</bool>
+ <bool name="always_true">true</bool>
+ <integer-array name="fibonacci">
+ <item>1</item>
+ <item>1</item>
+ <item>2</item>
+ <item>3</item>
+ <item>5</item>
+ <item>8</item>
+ <item>13</item>
+ <item>21</item>
+ </integer-array>
+ <integer-array name="prime_numbers">
+ <item>2</item>
+ <item>3</item>
+ <item>5</item>
+ <item>7</item>
+ <item>11</item>
+ <item>13</item>
+ <item>17</item>
+ <item>19</item>
+ </integer-array>
+</resources>
diff --git a/core/tests/overlaytests/OverlayTest/res/xml/integer.xml b/core/tests/overlaytests/OverlayTest/res/xml/integer.xml
new file mode 100644
index 0000000..9383daa
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/res/xml/integer.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<integer value="0"/>
diff --git a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
index 6211c1c..58b7db9 100644
--- a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
+++ b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
@@ -2,13 +2,21 @@
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
import android.test.AndroidTestCase;
+import android.util.AttributeSet;
+import android.util.Xml;
+import java.io.BufferedReader;
import java.io.InputStream;
+import java.io.InputStreamReader;
import java.util.Locale;
public abstract class OverlayBaseTest extends AndroidTestCase {
private Resources mResources;
- protected boolean mWithOverlay; // will be set by subclasses
+ protected int mMode; // will be set by subclasses
+ static final protected int MODE_NO_OVERLAY = 0;
+ static final protected int MODE_SINGLE_OVERLAY = 1;
+ static final protected int MODE_MULTIPLE_OVERLAYS = 2;
protected void setUp() {
mResources = getContext().getResources();
@@ -36,20 +44,82 @@
mResources.updateConfiguration(config, mResources.getDisplayMetrics());
}
- private void assertResource(int resId, boolean ewo, boolean ew) throws Throwable {
- boolean expected = mWithOverlay ? ew : ewo;
+ private boolean getExpected(boolean no, boolean so, boolean mo) {
+ switch (mMode) {
+ case MODE_NO_OVERLAY:
+ return no;
+ case MODE_SINGLE_OVERLAY:
+ return so;
+ case MODE_MULTIPLE_OVERLAYS:
+ return mo;
+ default:
+ fail("Unknown mode!");
+ return no;
+ }
+ }
+
+ private String getExpected(String no, String so, String mo) {
+ switch (mMode) {
+ case MODE_NO_OVERLAY:
+ return no;
+ case MODE_SINGLE_OVERLAY:
+ return so;
+ case MODE_MULTIPLE_OVERLAYS:
+ return mo;
+ default:
+ fail("Unknown mode!");
+ return no;
+ }
+ }
+
+ private int getExpected(int no, int so, int mo) {
+ switch (mMode) {
+ case MODE_NO_OVERLAY:
+ return no;
+ case MODE_SINGLE_OVERLAY:
+ return so;
+ case MODE_MULTIPLE_OVERLAYS:
+ return mo;
+ default:
+ fail("Unknown mode!");
+ return no;
+ }
+ }
+
+ private int[] getExpected(int[] no, int[] so, int[] mo) {
+ switch (mMode) {
+ case MODE_NO_OVERLAY:
+ return no;
+ case MODE_SINGLE_OVERLAY:
+ return so;
+ case MODE_MULTIPLE_OVERLAYS:
+ return mo;
+ default:
+ fail("Unknown mode!");
+ return no;
+ }
+ }
+
+ private void assertResource(int resId, boolean no, boolean so, boolean mo) throws Throwable {
+ boolean expected = getExpected(no, so, mo);
boolean actual = mResources.getBoolean(resId);
assertEquals(expected, actual);
}
- private void assertResource(int resId, String ewo, String ew) throws Throwable {
- String expected = mWithOverlay ? ew : ewo;
+ private void assertResource(int resId, int no, int so, int mo) throws Throwable {
+ int expected = getExpected(no, so, mo);
+ int actual = mResources.getInteger(resId);
+ assertEquals(expected, actual);
+ }
+
+ private void assertResource(int resId, String no, String so, String mo) throws Throwable {
+ String expected = getExpected(no, so, mo);
String actual = mResources.getString(resId);
assertEquals(expected, actual);
}
- private void assertResource(int resId, int[] ewo, int[] ew) throws Throwable {
- int[] expected = mWithOverlay ? ew : ewo;
+ private void assertResource(int resId, int[] no, int[] so, int[] mo) throws Throwable {
+ int[] expected = getExpected(no, so, mo);
int[] actual = mResources.getIntArray(resId);
assertEquals("length:", expected.length, actual.length);
for (int i = 0; i < actual.length; ++i) {
@@ -57,62 +127,334 @@
}
}
+ public void testFrameworkBooleanOverlay() throws Throwable {
+ // config_annoy_dianne has the value:
+ // - true when no overlay exists (MODE_NO_OVERLAY)
+ // - false when a single overlay exists (MODE_SINGLE_OVERLAY)
+ // - false when multiple overlays exists (MODE_MULTIPLE_OVERLAYS)
+ final int resId = com.android.internal.R.bool.config_annoy_dianne;
+ assertResource(resId, true, false, false);
+ }
+
public void testBooleanOverlay() throws Throwable {
- // config_automatic_brightness_available has overlay (default config)
- final int resId = com.android.internal.R.bool.config_automatic_brightness_available;
- assertResource(resId, false, true);
+ // usually_false has the value:
+ // - false when no overlay exists (MODE_NO_OVERLAY)
+ // - true when a single overlay exists (MODE_SINGLE_OVERLAY)
+ // - false when multiple overlays exists (MODE_MULTIPLE_OVERLAYS)
+ final int resId = R.bool.usually_false;
+ assertResource(resId, false, true, false);
}
public void testBoolean() throws Throwable {
- // config_annoy_dianne has no overlay
- final int resId = com.android.internal.R.bool.config_annoy_dianne;
- assertResource(resId, true, true);
- }
-
- public void testStringOverlay() throws Throwable {
- // phoneTypeCar has an overlay (default config), which shouldn't shadow
- // the Swedish translation
- final int resId = com.android.internal.R.string.phoneTypeCar;
- setLocale("sv_SE");
- assertResource(resId, "Bil", "Bil");
- }
-
- public void testStringSwedishOverlay() throws Throwable {
- // phoneTypeWork has overlay (no default config, only for lang=sv)
- final int resId = com.android.internal.R.string.phoneTypeWork;
- setLocale("en_US");
- assertResource(resId, "Work", "Work");
- setLocale("sv_SE");
- assertResource(resId, "Arbete", "Jobb");
- }
-
- public void testString() throws Throwable {
- // phoneTypeHome has no overlay
- final int resId = com.android.internal.R.string.phoneTypeHome;
- setLocale("en_US");
- assertResource(resId, "Home", "Home");
- setLocale("sv_SE");
- assertResource(resId, "Hem", "Hem");
+ // always_true has no overlay
+ final int resId = R.bool.always_true;
+ assertResource(resId, true, true, true);
}
public void testIntegerArrayOverlay() throws Throwable {
- // config_scrollBarrierVibePattern has overlay (default config)
- final int resId = com.android.internal.R.array.config_scrollBarrierVibePattern;
- assertResource(resId, new int[]{0, 15, 10, 10}, new int[]{100, 200, 300});
+ // fibonacci has values:
+ // - eight first values of Fibonacci sequence, when no overlay exists (MODE_NO_OVERLAY)
+ // - eight first values of Fibonacci sequence (reversed), for single and multiple overlays
+ // (MODE_SINGLE_OVERLAY, MODE_MULTIPLE_OVERLAYS)
+ final int resId = R.array.fibonacci;
+ assertResource(resId,
+ new int[]{1, 1, 2, 3, 5, 8, 13, 21},
+ new int[]{21, 13, 8, 5, 3, 2, 1, 1},
+ new int[]{21, 13, 8, 5, 3, 2, 1, 1});
}
public void testIntegerArray() throws Throwable {
- // config_virtualKeyVibePattern has no overlay
- final int resId = com.android.internal.R.array.config_virtualKeyVibePattern;
- final int[] expected = {0, 10, 20, 30};
- assertResource(resId, expected, expected);
+ // prime_numbers has no overlay
+ final int resId = R.array.prime_numbers;
+ final int[] expected = {2, 3, 5, 7, 11, 13, 17, 19};
+ assertResource(resId, expected, expected, expected);
}
- public void testAsset() throws Throwable {
- // drawable/default_background.jpg has overlay (default config)
- final int resId = com.android.internal.R.drawable.default_wallpaper;
+ public void testDrawable() throws Throwable {
+ // drawable-nodpi/drawable has overlay (default config)
+ final int resId = R.drawable.drawable;
int actual = calculateRawResourceChecksum(resId);
- int expected = mWithOverlay ? 0x000051da : 0x0014ebce;
+ int expected = 0;
+ switch (mMode) {
+ case MODE_NO_OVERLAY:
+ expected = 0x00005665;
+ break;
+ case MODE_SINGLE_OVERLAY:
+ case MODE_MULTIPLE_OVERLAYS:
+ expected = 0x000051da;
+ break;
+ default:
+ fail("Unknown mode " + mMode);
+ }
assertEquals(expected, actual);
}
+
+ public void testAppString() throws Throwable {
+ final int resId = R.string.str;
+ assertResource(resId, "none", "single", "multiple");
+ }
+
+ public void testApp2() throws Throwable {
+ final int resId = R.string.str2; // only in base package and first app overlay
+ assertResource(resId, "none", "single", "single");
+ }
+
+ public void testAppXml() throws Throwable {
+ int expected = getExpected(0, 1, 2);
+ int actual = -1;
+ XmlResourceParser parser = mResources.getXml(R.xml.integer);
+ int type = parser.getEventType();
+ while (type != XmlResourceParser.END_DOCUMENT && actual == -1) {
+ if (type == XmlResourceParser.START_TAG && "integer".equals(parser.getName())) {
+ AttributeSet as = Xml.asAttributeSet(parser);
+ actual = as.getAttributeIntValue(null, "value", -1);
+ }
+ type = parser.next();
+ }
+ parser.close();
+ assertEquals(expected, actual);
+ }
+
+ public void testAppRaw() throws Throwable {
+ final int resId = R.raw.lorem_ipsum;
+
+ InputStream input = null;
+ BufferedReader reader = null;
+ String actual = "";
+ try {
+ input = mResources.openRawResource(resId);
+ reader = new BufferedReader(new InputStreamReader(input));
+ actual = reader.readLine();
+ } finally {
+ reader.close();
+ input.close();
+ }
+
+ final String no = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, " +
+ "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. " +
+ "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip " +
+ "ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit " +
+ "esse cillum dolore eu fugiat nulla pariatur. " +
+ "Excepteur sint occaecat cupidatat non proident, " +
+ "sunt in culpa qui officia deserunt mollit anim id est laborum.";
+ final String so = "Lorem ipsum: single overlay.";
+ final String mo = "Lorem ipsum: multiple overlays.";
+
+ assertEquals(getExpected(no, so, mo), actual);
+ }
+
+ /*
+ * testMatrix* tests
+ *
+ * The naming convention textMatrixABCDEF refers to in which packages and
+ * which configurations a resource is defined (1 if the resource is
+ * defined). If defined, a slot is always given the same value.
+ *
+ * SLOT PACKAGE CONFIGURATION VALUE
+ * A target package (default) 100
+ * B target package -sv 200
+ * C OverlayAppFirst (default) 300
+ * D OverlayAppFirst -sv 400
+ * E OverlayAppSecond (default) 500
+ * F OverlayAppSecond -sv 600
+ *
+ * Example: in testMatrix101110, the base package defines the
+ * R.integer.matrix101110 resource for the default configuration (value
+ * 100), OverlayAppFirst defines it for both default and Swedish
+ * configurations (values 300 and 400, respectively), and OverlayAppSecond
+ * defines it for the default configuration (value 500). If both overlays
+ * are loaded, the expected value after setting the language to Swedish is
+ * 400.
+ */
+ public void testMatrix100000() throws Throwable {
+ final int resId = R.integer.matrix_100000;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 100, 100);
+ }
+
+ public void testMatrix100001() throws Throwable {
+ final int resId = R.integer.matrix_100001;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 100, 600);
+ }
+
+ public void testMatrix100010() throws Throwable {
+ final int resId = R.integer.matrix_100010;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 100, 500);
+ }
+
+ public void testMatrix100011() throws Throwable {
+ final int resId = R.integer.matrix_100011;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 100, 600);
+ }
+
+ public void testMatrix100100() throws Throwable {
+ final int resId = R.integer.matrix_100100;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 400, 400);
+ }
+
+ public void testMatrix100101() throws Throwable {
+ final int resId = R.integer.matrix_100101;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 400, 600);
+ }
+
+ public void testMatrix100110() throws Throwable {
+ final int resId = R.integer.matrix_100110;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 400, 400);
+ }
+
+ public void testMatrix100111() throws Throwable {
+ final int resId = R.integer.matrix_100111;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 400, 600);
+ }
+
+ public void testMatrix101000() throws Throwable {
+ final int resId = R.integer.matrix_101000;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 300, 300);
+ }
+
+ public void testMatrix101001() throws Throwable {
+ final int resId = R.integer.matrix_101001;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 300, 600);
+ }
+
+ public void testMatrix101010() throws Throwable {
+ final int resId = R.integer.matrix_101010;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 300, 500);
+ }
+
+ public void testMatrix101011() throws Throwable {
+ final int resId = R.integer.matrix_101011;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 300, 600);
+ }
+
+ public void testMatrix101100() throws Throwable {
+ final int resId = R.integer.matrix_101100;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 400, 400);
+ }
+
+ public void testMatrix101101() throws Throwable {
+ final int resId = R.integer.matrix_101101;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 400, 600);
+ }
+
+ public void testMatrix101110() throws Throwable {
+ final int resId = R.integer.matrix_101110;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 400, 400);
+ }
+
+ public void testMatrix101111() throws Throwable {
+ final int resId = R.integer.matrix_101111;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 400, 600);
+ }
+
+ public void testMatrix110000() throws Throwable {
+ final int resId = R.integer.matrix_110000;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 200, 200);
+ }
+
+ public void testMatrix110001() throws Throwable {
+ final int resId = R.integer.matrix_110001;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 200, 600);
+ }
+
+ public void testMatrix110010() throws Throwable {
+ final int resId = R.integer.matrix_110010;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 200, 200);
+ }
+
+ public void testMatrix110011() throws Throwable {
+ final int resId = R.integer.matrix_110011;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 200, 600);
+ }
+
+ public void testMatrix110100() throws Throwable {
+ final int resId = R.integer.matrix_110100;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 400, 400);
+ }
+
+ public void testMatrix110101() throws Throwable {
+ final int resId = R.integer.matrix_110101;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 400, 600);
+ }
+
+ public void testMatrix110110() throws Throwable {
+ final int resId = R.integer.matrix_110110;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 400, 400);
+ }
+
+ public void testMatrix110111() throws Throwable {
+ final int resId = R.integer.matrix_110111;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 400, 600);
+ }
+
+ public void testMatrix111000() throws Throwable {
+ final int resId = R.integer.matrix_111000;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 200, 200);
+ }
+
+ public void testMatrix111001() throws Throwable {
+ final int resId = R.integer.matrix_111001;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 200, 600);
+ }
+
+ public void testMatrix111010() throws Throwable {
+ final int resId = R.integer.matrix_111010;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 200, 200);
+ }
+
+ public void testMatrix111011() throws Throwable {
+ final int resId = R.integer.matrix_111011;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 200, 600);
+ }
+
+ public void testMatrix111100() throws Throwable {
+ final int resId = R.integer.matrix_111100;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 400, 400);
+ }
+
+ public void testMatrix111101() throws Throwable {
+ final int resId = R.integer.matrix_111101;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 400, 600);
+ }
+
+ public void testMatrix111110() throws Throwable {
+ final int resId = R.integer.matrix_111110;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 400, 400);
+ }
+
+ public void testMatrix111111() throws Throwable {
+ final int resId = R.integer.matrix_111111;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 400, 600);
+ }
}
diff --git a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithMultipleOverlaysTest.java b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithMultipleOverlaysTest.java
new file mode 100644
index 0000000..e104f5a
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithMultipleOverlaysTest.java
@@ -0,0 +1,7 @@
+package com.android.overlaytest;
+
+public class WithMultipleOverlaysTest extends OverlayBaseTest {
+ public WithMultipleOverlaysTest() {
+ mMode = MODE_MULTIPLE_OVERLAYS;
+ }
+}
diff --git a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java
index 1292d03..816a476 100644
--- a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java
+++ b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java
@@ -2,6 +2,6 @@
public class WithOverlayTest extends OverlayBaseTest {
public WithOverlayTest() {
- mWithOverlay = true;
+ mMode = MODE_SINGLE_OVERLAY;
}
}
diff --git a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java
index 630ff8f..318cccc 100644
--- a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java
+++ b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java
@@ -2,6 +2,6 @@
public class WithoutOverlayTest extends OverlayBaseTest {
public WithoutOverlayTest() {
- mWithOverlay = false;
+ mMode = MODE_NO_OVERLAY;
}
}
diff --git a/core/tests/overlaytests/OverlayTestOverlay/AndroidManifest.xml b/core/tests/overlaytests/OverlayTestOverlay/AndroidManifest.xml
index bcbb0d1..f8b6c7b 100644
--- a/core/tests/overlaytests/OverlayTestOverlay/AndroidManifest.xml
+++ b/core/tests/overlaytests/OverlayTestOverlay/AndroidManifest.xml
@@ -2,5 +2,5 @@
package="com.android.overlaytest.overlay"
android:versionCode="1"
android:versionName="1.0">
- <overlay-package android:name="android"/>
+ <overlay android:targetPackage="android" android:priority="1"/>
</manifest>
diff --git a/core/tests/overlaytests/OverlayTestOverlay/res/values-sv/config.xml b/core/tests/overlaytests/OverlayTestOverlay/res/values-sv/config.xml
deleted file mode 100644
index bc52367..0000000
--- a/core/tests/overlaytests/OverlayTestOverlay/res/values-sv/config.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <string name="phoneTypeWork">Jobb</string>
-</resources>
diff --git a/core/tests/overlaytests/OverlayTestOverlay/res/values/config.xml b/core/tests/overlaytests/OverlayTestOverlay/res/values/config.xml
index 794f475..c1e3de1 100644
--- a/core/tests/overlaytests/OverlayTestOverlay/res/values/config.xml
+++ b/core/tests/overlaytests/OverlayTestOverlay/res/values/config.xml
@@ -1,13 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <bool name="config_automatic_brightness_available">true</bool>
- <string name="phoneTypeCar">Automobile</string>
- <integer-array name="config_scrollBarrierVibePattern">
- <item>100</item>
- <item>200</item>
- <item>300</item>
- </integer-array>
- <!-- The following integer does not exist in the original package. Idmap
- generation should therefore ignore it. -->
- <integer name="integer_not_in_original_package">0</integer>
+ <bool name="config_annoy_dianne">false</bool>
</resources>
diff --git a/core/tests/overlaytests/README b/core/tests/overlaytests/README
deleted file mode 100644
index 4b3e6f2..0000000
--- a/core/tests/overlaytests/README
+++ /dev/null
@@ -1,15 +0,0 @@
-Unit tests for runtime resource overlay
-=======================================
-
-As of this writing, runtime resource overlay is only triggered for
-/system/framework/framework-res.apk. Because of this, installation of
-overlay packages require the Android platform be rebooted. However, the
-regular unit tests (triggered via development/testrunner/runtest.py)
-cannot handle reboots. As a workaround, this directory contains a shell
-script which will trigger the tests in a non-standard way.
-
-Once runtime resource overlay may be applied to applications, the tests
-in this directory should be moved to core/tests/coretests. Also, by
-applying runtime resource overlay to a dedicated test application, the
-test cases would not need to assume default values for non-overlaid
-resources.
diff --git a/core/tests/overlaytests/runtests.sh b/core/tests/overlaytests/runtests.sh
deleted file mode 100755
index 0a721ad40..0000000
--- a/core/tests/overlaytests/runtests.sh
+++ /dev/null
@@ -1,129 +0,0 @@
-#!/bin/bash
-
-adb="adb"
-if [[ $# -gt 0 ]]; then
- adb="adb $*" # for setting -e, -d or -s <serial>
-fi
-
-function atexit()
-{
- local retval=$?
-
- if [[ $retval -eq 0 ]]; then
- rm $log
- else
- echo "There were errors, please check log at $log"
- fi
-}
-
-log=$(mktemp)
-trap "atexit" EXIT
-
-function compile_module()
-{
- local android_mk="$1"
-
- echo "Compiling .${android_mk:${#PWD}}"
- ONE_SHOT_MAKEFILE="$android_mk" make -C "../../../../../" files | tee -a $log
- if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
- exit 1
- fi
-}
-
-function wait_for_boot_completed()
-{
- echo "Rebooting device"
- $adb wait-for-device logcat -c
- $adb wait-for-device logcat | grep -m 1 -e 'PowerManagerService.*bootCompleted' >/dev/null
-}
-
-function mkdir_if_needed()
-{
- local path="$1"
-
- if [[ "${path:0:1}" != "/" ]]; then
- echo "mkdir_if_needed: error: path '$path' does not begin with /" | tee -a $log
- exit 1
- fi
-
- local basename=$(basename "$path")
- local dirname=$(dirname "$path")
- local t=$($adb shell ls -l $dirname | tr -d '\r' | grep -e "${basename}$" | grep -oe '^.')
-
- case "$t" in
- d) # File exists, and is a directory ...
- # do nothing
- ;;
- l) # ... (or symbolic link possibly to a directory).
- # do nothing
- ;;
- "") # File does not exist.
- mkdir_if_needed "$dirname"
- $adb shell mkdir "$path"
- ;;
- *) # File exists, but is not a directory.
- echo "mkdir_if_needed: file '$path' exists, but is not a directory" | tee -a $log
- exit 1
- ;;
- esac
-}
-
-function disable_overlay()
-{
- echo "Disabling overlay"
- $adb shell rm /vendor/overlay/framework/framework-res.apk
- $adb shell rm /data/resource-cache/vendor@overlay@framework@framework-res.apk@idmap
-}
-
-function enable_overlay()
-{
- echo "Enabling overlay"
- mkdir_if_needed "/system/vendor"
- mkdir_if_needed "/vendor/overlay/framework"
- $adb shell ln -s /data/app/com.android.overlaytest.overlay.apk /vendor/overlay/framework/framework-res.apk
-}
-
-function instrument()
-{
- local class="$1"
-
- echo "Instrumenting $class"
- $adb shell am instrument -w -e class $class com.android.overlaytest/android.test.InstrumentationTestRunner | tee -a $log
-}
-
-function remount()
-{
- echo "Remounting file system writable"
- $adb remount | tee -a $log
-}
-
-function sync()
-{
- echo "Syncing to device"
- $adb sync data | tee -a $log
-}
-
-# some commands require write access, remount once and for all
-remount
-
-# build and sync
-compile_module "$PWD/OverlayTest/Android.mk"
-compile_module "$PWD/OverlayTestOverlay/Android.mk"
-sync
-
-# instrument test (without overlay)
-$adb shell stop
-disable_overlay
-$adb shell start
-wait_for_boot_completed
-instrument "com.android.overlaytest.WithoutOverlayTest"
-
-# instrument test (with overlay)
-$adb shell stop
-enable_overlay
-$adb shell start
-wait_for_boot_completed
-instrument "com.android.overlaytest.WithOverlayTest"
-
-# cleanup
-exit $(grep -c -e '^FAILURES' $log)
diff --git a/core/tests/overlaytests/testrunner.py b/core/tests/overlaytests/testrunner.py
new file mode 100755
index 0000000..4f94373
--- /dev/null
+++ b/core/tests/overlaytests/testrunner.py
@@ -0,0 +1,679 @@
+#!/usr/bin/python
+import hashlib
+import optparse
+import os
+import re
+import shlex
+import subprocess
+import sys
+import threading
+import time
+
+TASK_COMPILATION = 'compile'
+TASK_DISABLE_OVERLAYS = 'disable overlays'
+TASK_ENABLE_MULTIPLE_OVERLAYS = 'enable multiple overlays'
+TASK_ENABLE_SINGLE_OVERLAY = 'enable single overlay'
+TASK_FILE_EXISTS_TEST = 'test (file exists)'
+TASK_GREP_IDMAP_TEST = 'test (grep idmap)'
+TASK_MD5_TEST = 'test (md5)'
+TASK_IDMAP_PATH = 'idmap --path'
+TASK_IDMAP_SCAN = 'idmap --scan'
+TASK_INSTRUMENTATION = 'instrumentation'
+TASK_INSTRUMENTATION_TEST = 'test (instrumentation)'
+TASK_MKDIR = 'mkdir'
+TASK_PUSH = 'push'
+TASK_ROOT = 'root'
+TASK_REMOUNT = 'remount'
+TASK_RM = 'rm'
+TASK_SETUP_IDMAP_PATH = 'setup idmap --path'
+TASK_SETUP_IDMAP_SCAN = 'setup idmap --scan'
+TASK_START = 'start'
+TASK_STOP = 'stop'
+
+adb = 'adb'
+
+def _adb_shell(cmd):
+ argv = shlex.split(adb + " shell '" + cmd + "; echo $?'")
+ proc = subprocess.Popen(argv, bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stdout, stderr) = proc.communicate()
+ (stdout, stderr) = (stdout.replace('\r', ''), stderr.replace('\r', ''))
+ tmp = stdout.rsplit('\n', 2)
+ if len(tmp) == 2:
+ stdout == ''
+ returncode = int(tmp[0])
+ else:
+ stdout = tmp[0] + '\n'
+ returncode = int(tmp[1])
+ return returncode, stdout, stderr
+
+class VerbosePrinter:
+ class Ticker(threading.Thread):
+ def _print(self):
+ s = '\r' + self.text + '[' + '.' * self.i + ' ' * (4 - self.i) + ']'
+ sys.stdout.write(s)
+ sys.stdout.flush()
+ self.i = (self.i + 1) % 5
+
+ def __init__(self, cond_var, text):
+ threading.Thread.__init__(self)
+ self.text = text
+ self.setDaemon(True)
+ self.cond_var = cond_var
+ self.running = False
+ self.i = 0
+ self._print()
+ self.running = True
+
+ def run(self):
+ self.cond_var.acquire()
+ while True:
+ self.cond_var.wait(0.25)
+ running = self.running
+ if not running:
+ break
+ self._print()
+ self.cond_var.release()
+
+ def stop(self):
+ self.cond_var.acquire()
+ self.running = False
+ self.cond_var.notify_all()
+ self.cond_var.release()
+
+ def _start_ticker(self):
+ self.ticker = VerbosePrinter.Ticker(self.cond_var, self.text)
+ self.ticker.start()
+
+ def _stop_ticker(self):
+ self.ticker.stop()
+ self.ticker.join()
+ self.ticker = None
+
+ def _format_begin(self, type, name):
+ N = self.width - len(type) - len(' [ ] ')
+ fmt = '%%s %%-%ds ' % N
+ return fmt % (type, name)
+
+ def __init__(self, use_color):
+ self.cond_var = threading.Condition()
+ self.ticker = None
+ if use_color:
+ self.color_RED = '\033[1;31m'
+ self.color_red = '\033[0;31m'
+ self.color_reset = '\033[0;37m'
+ else:
+ self.color_RED = ''
+ self.color_red = ''
+ self.color_reset = ''
+
+ argv = shlex.split('stty size') # get terminal width
+ proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stdout, stderr) = proc.communicate()
+ if proc.returncode == 0:
+ (h, w) = stdout.split()
+ self.width = int(w)
+ else:
+ self.width = 72 # conservative guesstimate
+
+ def begin(self, type, name):
+ self.text = self._format_begin(type, name)
+ sys.stdout.write(self.text + '[ ]')
+ sys.stdout.flush()
+ self._start_ticker()
+
+ def end_pass(self, type, name):
+ self._stop_ticker()
+ sys.stdout.write('\r' + self.text + '[ OK ]\n')
+ sys.stdout.flush()
+
+ def end_fail(self, type, name, msg):
+ self._stop_ticker()
+ sys.stdout.write('\r' + self.color_RED + self.text + '[FAIL]\n')
+ sys.stdout.write(self.color_red)
+ sys.stdout.write(msg)
+ sys.stdout.write(self.color_reset)
+ sys.stdout.flush()
+
+class QuietPrinter:
+ def begin(self, type, name):
+ pass
+
+ def end_pass(self, type, name):
+ sys.stdout.write('PASS ' + type + ' ' + name + '\n')
+ sys.stdout.flush()
+
+ def end_fail(self, type, name, msg):
+ sys.stdout.write('FAIL ' + type + ' ' + name + '\n')
+ sys.stdout.flush()
+
+class CompilationTask:
+ def __init__(self, makefile):
+ self.makefile = makefile
+
+ def get_type(self):
+ return TASK_COMPILATION
+
+ def get_name(self):
+ return self.makefile
+
+ def execute(self):
+ os.putenv('ONE_SHOT_MAKEFILE', os.getcwd() + "/" + self.makefile)
+ argv = shlex.split('make -C "../../../../../" files')
+ proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stdout, stderr) = proc.communicate()
+ return proc.returncode, stdout, stderr
+
+class InstrumentationTask:
+ def __init__(self, instrumentation_class):
+ self.instrumentation_class = instrumentation_class
+
+ def get_type(self):
+ return TASK_INSTRUMENTATION
+
+ def get_name(self):
+ return self.instrumentation_class
+
+ def execute(self):
+ return _adb_shell('am instrument -r -w -e class %s com.android.overlaytest/android.test.InstrumentationTestRunner' % self.instrumentation_class)
+
+class PushTask:
+ def __init__(self, src, dest):
+ self.src = src
+ self.dest = dest
+
+ def get_type(self):
+ return TASK_PUSH
+
+ def get_name(self):
+ return "%s -> %s" % (self.src, self.dest)
+
+ def execute(self):
+ src = os.getenv('OUT') + "/" + self.src
+ argv = shlex.split(adb + ' push %s %s' % (src, self.dest))
+ proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stdout, stderr) = proc.communicate()
+ return proc.returncode, stdout, stderr
+
+class MkdirTask:
+ def __init__(self, path):
+ self.path = path
+
+ def get_type(self):
+ return TASK_MKDIR
+
+ def get_name(self):
+ return self.path
+
+ def execute(self):
+ return _adb_shell('mkdir -p %s' % self.path)
+
+class RmTask:
+ def __init__(self, path):
+ self.path = path
+
+ def get_type(self):
+ return TASK_RM
+
+ def get_name(self):
+ return self.path
+
+ def execute(self):
+ returncode, stdout, stderr = _adb_shell('ls %s' % self.path)
+ if returncode != 0 and stdout.endswith(': No such file or directory\n'):
+ return 0, "", ""
+ return _adb_shell('rm -r %s' % self.path)
+
+class IdmapPathTask:
+ def __init__(self, path_target_apk, path_overlay_apk, path_idmap):
+ self.path_target_apk = path_target_apk
+ self.path_overlay_apk = path_overlay_apk
+ self.path_idmap = path_idmap
+
+ def get_type(self):
+ return TASK_IDMAP_PATH
+
+ def get_name(self):
+ return self.path_idmap
+
+ def execute(self):
+ return _adb_shell('su system idmap --path "%s" "%s" "%s"' % (self.path_target_apk, self.path_overlay_apk, self.path_idmap))
+
+class IdmapScanTask:
+ def __init__(self, overlay_dir, target_pkg_name, target_pkg, idmap_dir, symlink_dir):
+ self.overlay_dir = overlay_dir
+ self.target_pkg_name = target_pkg_name
+ self.target_pkg = target_pkg
+ self.idmap_dir = idmap_dir
+ self.symlink_dir = symlink_dir
+
+ def get_type(self):
+ return TASK_IDMAP_SCAN
+
+ def get_name(self):
+ return self.target_pkg_name
+
+ def execute(self):
+ return _adb_shell('su system idmap --scan "%s" "%s" "%s" "%s"' % (self.overlay_dir, self.target_pkg_name, self.target_pkg, self.idmap_dir))
+
+class FileExistsTest:
+ def __init__(self, path):
+ self.path = path
+
+ def get_type(self):
+ return TASK_FILE_EXISTS_TEST
+
+ def get_name(self):
+ return self.path
+
+ def execute(self):
+ return _adb_shell('ls %s' % self.path)
+
+class GrepIdmapTest:
+ def __init__(self, path_idmap, pattern, expected_n):
+ self.path_idmap = path_idmap
+ self.pattern = pattern
+ self.expected_n = expected_n
+
+ def get_type(self):
+ return TASK_GREP_IDMAP_TEST
+
+ def get_name(self):
+ return self.pattern
+
+ def execute(self):
+ returncode, stdout, stderr = _adb_shell('idmap --inspect %s' % self.path_idmap)
+ if returncode != 0:
+ return returncode, stdout, stderr
+ all_matches = re.findall('\s' + self.pattern + '$', stdout, flags=re.MULTILINE)
+ if len(all_matches) != self.expected_n:
+ return 1, 'pattern=%s idmap=%s expected=%d found=%d\n' % (self.pattern, self.path_idmap, self.expected_n, len(all_matches)), ''
+ return 0, "", ""
+
+class Md5Test:
+ def __init__(self, path, expected_content):
+ self.path = path
+ self.expected_md5 = hashlib.md5(expected_content).hexdigest()
+
+ def get_type(self):
+ return TASK_MD5_TEST
+
+ def get_name(self):
+ return self.path
+
+ def execute(self):
+ returncode, stdout, stderr = _adb_shell('md5 %s' % self.path)
+ if returncode != 0:
+ return returncode, stdout, stderr
+ actual_md5 = stdout.split()[0]
+ if actual_md5 != self.expected_md5:
+ return 1, 'expected %s, got %s\n' % (self.expected_md5, actual_md5), ''
+ return 0, "", ""
+
+class StartTask:
+ def get_type(self):
+ return TASK_START
+
+ def get_name(self):
+ return ""
+
+ def execute(self):
+ (returncode, stdout, stderr) = _adb_shell('start')
+ if returncode != 0:
+ return returncode, stdout, stderr
+
+ while True:
+ (returncode, stdout, stderr) = _adb_shell('getprop dev.bootcomplete')
+ if returncode != 0:
+ return returncode, stdout, stderr
+ if stdout.strip() == "1":
+ break
+ time.sleep(0.5)
+
+ return 0, "", ""
+
+class StopTask:
+ def get_type(self):
+ return TASK_STOP
+
+ def get_name(self):
+ return ""
+
+ def execute(self):
+ (returncode, stdout, stderr) = _adb_shell('stop')
+ if returncode != 0:
+ return returncode, stdout, stderr
+ return _adb_shell('setprop dev.bootcomplete 0')
+
+class RootTask:
+ def get_type(self):
+ return TASK_ROOT
+
+ def get_name(self):
+ return ""
+
+ def execute(self):
+ (returncode, stdout, stderr) = _adb_shell('getprop service.adb.root 0')
+ if returncode != 0:
+ return returncode, stdout, stderr
+ if stdout.strip() == '1': # already root
+ return 0, "", ""
+
+ argv = shlex.split(adb + ' root')
+ proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stdout, stderr) = proc.communicate()
+ if proc.returncode != 0:
+ return proc.returncode, stdout, stderr
+
+ argv = shlex.split(adb + ' wait-for-device')
+ proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stdout, stderr) = proc.communicate()
+ return proc.returncode, stdout, stderr
+
+class RemountTask:
+ def get_type(self):
+ return TASK_REMOUNT
+
+ def get_name(self):
+ return ""
+
+ def execute(self):
+ argv = shlex.split(adb + ' remount')
+ proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stdout, stderr) = proc.communicate()
+ # adb remount returns 0 even if the operation failed, so check stdout
+ if stdout.startswith('remount failed:'):
+ return 1, stdout, stderr
+ return proc.returncode, stdout, stderr
+
+class CompoundTask:
+ def __init__(self, type, tasks):
+ self.type = type
+ self.tasks = tasks
+
+ def get_type(self):
+ return self.type
+
+ def get_name(self):
+ return ""
+
+ def execute(self):
+ for t in self.tasks:
+ (returncode, stdout, stderr) = t.execute()
+ if returncode != 0:
+ return returncode, stdout, stderr
+ return 0, "", ""
+
+def _create_disable_overlays_task():
+ tasks = [
+ RmTask("/vendor/overlay/framework_a.apk"),
+ RmTask("/vendor/overlay/framework_b.apk"),
+ RmTask("/data/resource-cache/vendor@overlay@framework_a.apk@idmap"),
+ RmTask("/data/resource-cache/vendor@overlay@framework_b.apk@idmap"),
+ RmTask("/vendor/overlay/app_a.apk"),
+ RmTask("/vendor/overlay/app_b.apk"),
+ RmTask("/data/resource-cache/vendor@overlay@app_a.apk@idmap"),
+ RmTask("/data/resource-cache/vendor@overlay@app_b.apk@idmap"),
+ ]
+ return CompoundTask(TASK_DISABLE_OVERLAYS, tasks)
+
+def _create_enable_single_overlay_task():
+ tasks = [
+ _create_disable_overlays_task(),
+ MkdirTask('/system/vendor'),
+ MkdirTask('/vendor/overlay'),
+ PushTask('/data/app/com.android.overlaytest.overlay.apk', '/vendor/overlay/framework_a.apk'),
+ PushTask('/data/app/com.android.overlaytest.first_app_overlay.apk', '/vendor/overlay/app_a.apk'),
+ ]
+ return CompoundTask(TASK_ENABLE_SINGLE_OVERLAY, tasks)
+
+def _create_enable_multiple_overlays_task():
+ tasks = [
+ _create_disable_overlays_task(),
+ MkdirTask('/system/vendor'),
+ MkdirTask('/vendor/overlay'),
+
+ PushTask('/data/app/com.android.overlaytest.overlay.apk', '/vendor/overlay/framework_b.apk'),
+ PushTask('/data/app/com.android.overlaytest.first_app_overlay.apk', '/vendor/overlay/app_a.apk'),
+ PushTask('/data/app/com.android.overlaytest.second_app_overlay.apk', '/vendor/overlay/app_b.apk'),
+ ]
+ return CompoundTask(TASK_ENABLE_MULTIPLE_OVERLAYS, tasks)
+
+def _create_setup_idmap_path_task(idmaps, symlinks):
+ tasks = [
+ _create_enable_single_overlay_task(),
+ RmTask(symlinks),
+ RmTask(idmaps),
+ MkdirTask(idmaps),
+ MkdirTask(symlinks),
+ ]
+ return CompoundTask(TASK_SETUP_IDMAP_PATH, tasks)
+
+def _create_setup_idmap_scan_task(idmaps, symlinks):
+ tasks = [
+ _create_enable_single_overlay_task(),
+ RmTask(symlinks),
+ RmTask(idmaps),
+ MkdirTask(idmaps),
+ MkdirTask(symlinks),
+ _create_enable_multiple_overlays_task(),
+ ]
+ return CompoundTask(TASK_SETUP_IDMAP_SCAN, tasks)
+
+def _handle_instrumentation_task_output(stdout, printer):
+ regex_status_code = re.compile(r'^INSTRUMENTATION_STATUS_CODE: -?(\d+)')
+ regex_name = re.compile(r'^INSTRUMENTATION_STATUS: test=(.*)')
+ regex_begin_stack = re.compile(r'^INSTRUMENTATION_STATUS: stack=(.*)')
+ regex_end_stack = re.compile(r'^$')
+
+ failed_tests = 0
+ current_test = None
+ current_stack = []
+ mode_stack = False
+ for line in stdout.split("\n"):
+ line = line.rstrip() # strip \r from adb output
+ m = regex_status_code.match(line)
+ if m:
+ c = int(m.group(1))
+ if c == 1:
+ printer.begin(TASK_INSTRUMENTATION_TEST, current_test)
+ elif c == 0:
+ printer.end_pass(TASK_INSTRUMENTATION_TEST, current_test)
+ else:
+ failed_tests += 1
+ current_stack.append("\n")
+ msg = "\n".join(current_stack)
+ printer.end_fail(TASK_INSTRUMENTATION_TEST, current_test, msg.rstrip() + '\n')
+ continue
+
+ m = regex_name.match(line)
+ if m:
+ current_test = m.group(1)
+ continue
+
+ m = regex_begin_stack.match(line)
+ if m:
+ mode_stack = True
+ current_stack = []
+ current_stack.append(" " + m.group(1))
+ continue
+
+ m = regex_end_stack.match(line)
+ if m:
+ mode_stack = False
+ continue
+
+ if mode_stack:
+ current_stack.append(" " + line.strip())
+
+ return failed_tests
+
+def _set_adb_device(option, opt, value, parser):
+ global adb
+ if opt == '-d' or opt == '--device':
+ adb = 'adb -d'
+ if opt == '-e' or opt == '--emulator':
+ adb = 'adb -e'
+ if opt == '-s' or opt == '--serial':
+ adb = 'adb -s ' + value
+
+def _create_opt_parser():
+ parser = optparse.OptionParser()
+ parser.add_option('-d', '--device', action='callback', callback=_set_adb_device,
+ help='pass -d to adb')
+ parser.add_option('-e', '--emulator', action='callback', callback=_set_adb_device,
+ help='pass -e to adb')
+ parser.add_option('-s', '--serial', type="str", action='callback', callback=_set_adb_device,
+ help='pass -s <serical> to adb')
+ parser.add_option('-C', '--no-color', action='store_false',
+ dest='use_color', default=True,
+ help='disable color escape sequences in output')
+ parser.add_option('-q', '--quiet', action='store_true',
+ dest='quiet_mode', default=False,
+ help='quiet mode, output only results')
+ parser.add_option('-b', '--no-build', action='store_false',
+ dest='do_build', default=True,
+ help='do not rebuild test projects')
+ parser.add_option('-k', '--continue', action='store_true',
+ dest='do_continue', default=False,
+ help='do not rebuild test projects')
+ parser.add_option('-i', '--test-idmap', action='store_true',
+ dest='test_idmap', default=False,
+ help='run tests for single overlay')
+ parser.add_option('-0', '--test-no-overlay', action='store_true',
+ dest='test_no_overlay', default=False,
+ help='run tests without any overlay')
+ parser.add_option('-1', '--test-single-overlay', action='store_true',
+ dest='test_single_overlay', default=False,
+ help='run tests for single overlay')
+ parser.add_option('-2', '--test-multiple-overlays', action='store_true',
+ dest='test_multiple_overlays', default=False,
+ help='run tests for multiple overlays')
+ return parser
+
+if __name__ == '__main__':
+ opt_parser = _create_opt_parser()
+ opts, args = opt_parser.parse_args(sys.argv[1:])
+ if not opts.test_idmap and not opts.test_no_overlay and not opts.test_single_overlay and not opts.test_multiple_overlays:
+ opts.test_idmap = True
+ opts.test_no_overlay = True
+ opts.test_single_overlay = True
+ opts.test_multiple_overlays = True
+ if len(args) > 0:
+ opt_parser.error("unexpected arguments: %s" % " ".join(args))
+ # will never reach this: opt_parser.error will call sys.exit
+
+ if opts.quiet_mode:
+ printer = QuietPrinter()
+ else:
+ printer = VerbosePrinter(opts.use_color)
+ tasks = []
+
+ # must be in the same directory as this script for compilation tasks to work
+ script = sys.argv[0]
+ dirname = os.path.dirname(script)
+ wd = os.path.realpath(dirname)
+ os.chdir(wd)
+
+ # build test cases
+ if opts.do_build:
+ tasks.append(CompilationTask('OverlayTest/Android.mk'))
+ tasks.append(CompilationTask('OverlayTestOverlay/Android.mk'))
+ tasks.append(CompilationTask('OverlayAppFirst/Android.mk'))
+ tasks.append(CompilationTask('OverlayAppSecond/Android.mk'))
+
+ # remount filesystem, install test project
+ tasks.append(RootTask())
+ tasks.append(RemountTask())
+ tasks.append(PushTask('/system/app/OverlayTest.apk', '/system/app/OverlayTest.apk'))
+
+ # test idmap
+ if opts.test_idmap:
+ idmaps='/data/local/tmp/idmaps'
+ symlinks='/data/local/tmp/symlinks'
+
+ # idmap --path
+ tasks.append(StopTask())
+ tasks.append(_create_setup_idmap_path_task(idmaps, symlinks))
+ tasks.append(StartTask())
+ tasks.append(IdmapPathTask('/vendor/overlay/framework_a.apk', '/system/framework/framework-res.apk', idmaps + '/a.idmap'))
+ tasks.append(FileExistsTest(idmaps + '/a.idmap'))
+ tasks.append(GrepIdmapTest(idmaps + '/a.idmap', 'bool/config_annoy_dianne', 1))
+
+ # idmap --scan
+ idmap = idmaps + '/vendor@overlay@framework_b.apk@idmap'
+ tasks.append(StopTask())
+ tasks.append(_create_setup_idmap_scan_task(idmaps, symlinks))
+ tasks.append(StartTask())
+ tasks.append(IdmapScanTask('/vendor/overlay', 'android', '/system/framework/framework-res.apk', idmaps, symlinks))
+ tasks.append(FileExistsTest(idmap))
+ tasks.append(GrepIdmapTest(idmap, 'bool/config_annoy_dianne', 1))
+
+ # overlays.list
+ overlays_list_path = '/data/resource-cache/overlays.list'
+ expected_content = '''\
+/vendor/overlay/framework_b.apk /data/resource-cache/vendor@overlay@framework_b.apk@idmap
+'''
+ tasks.append(FileExistsTest(overlays_list_path))
+ tasks.append(Md5Test(overlays_list_path, expected_content))
+
+ # idmap cleanup
+ tasks.append(RmTask(symlinks))
+ tasks.append(RmTask(idmaps))
+
+ # test no overlay
+ if opts.test_no_overlay:
+ tasks.append(StopTask())
+ tasks.append(_create_disable_overlays_task())
+ tasks.append(StartTask())
+ tasks.append(InstrumentationTask('com.android.overlaytest.WithoutOverlayTest'))
+
+ # test single overlay
+ if opts.test_single_overlay:
+ tasks.append(StopTask())
+ tasks.append(_create_enable_single_overlay_task())
+ tasks.append(StartTask())
+ tasks.append(InstrumentationTask('com.android.overlaytest.WithOverlayTest'))
+
+ # test multiple overlays
+ if opts.test_multiple_overlays:
+ tasks.append(StopTask())
+ tasks.append(_create_enable_multiple_overlays_task())
+ tasks.append(StartTask())
+ tasks.append(InstrumentationTask('com.android.overlaytest.WithMultipleOverlaysTest'))
+
+ ignored_errors = 0
+ for t in tasks:
+ type = t.get_type()
+ name = t.get_name()
+ if type == TASK_INSTRUMENTATION:
+ # InstrumentationTask will run several tests, but we want it
+ # to appear as if each test was run individually. Calling
+ # "am instrument" with a single test method is prohibitively
+ # expensive, so let's instead post-process the output to
+ # emulate individual calls.
+ retcode, stdout, stderr = t.execute()
+ if retcode != 0:
+ printer.begin(TASK_INSTRUMENTATION, name)
+ printer.end_fail(TASK_INSTRUMENTATION, name, stderr)
+ sys.exit(retcode)
+ retcode = _handle_instrumentation_task_output(stdout, printer)
+ if retcode != 0:
+ if not opts.do_continue:
+ sys.exit(retcode)
+ else:
+ ignored_errors += retcode
+ else:
+ printer.begin(type, name)
+ retcode, stdout, stderr = t.execute()
+ if retcode == 0:
+ printer.end_pass(type, name)
+ if retcode != 0:
+ if len(stderr) == 0:
+ # hope for output from stdout instead (true for eg adb shell rm)
+ stderr = stdout
+ printer.end_fail(type, name, stderr)
+ if not opts.do_continue:
+ sys.exit(retcode)
+ else:
+ ignored_errors += retcode
+ sys.exit(ignored_errors)