am 49724e7c: am 0d4a4a3b: am d35f8eb4: Adding CTS test samples device- and host-side tests.
* commit '49724e7c3e1ee1fc23007a84c0c4ff767a94e01f':
Adding CTS test samples device- and host-side tests.
diff --git a/CtsBuild.mk b/CtsBuild.mk
index 6e57086..f6d0d5c 100644
--- a/CtsBuild.mk
+++ b/CtsBuild.mk
@@ -51,3 +51,7 @@
define cts-get-test-xmls
$(foreach name,$(1),$(CTS_TESTCASES_OUT)/$(name).xml)
endef
+
+define cts-get-executable-paths
+ $(foreach executable,$(1),$(CTS_TESTCASES_OUT)/$(executable))
+endef
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index dbf82c9..bc29b27 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -103,6 +103,7 @@
CtsPermission2TestCases \
CtsPreferenceTestCases \
CtsPreference2TestCases \
+ CtsPrintTestCases \
CtsProviderTestCases \
CtsRenderscriptTestCases \
CtsRenderscriptGraphicsTestCases \
@@ -139,13 +140,17 @@
cts_native_exes := \
NativeMediaTest_SL \
NativeMediaTest_XA \
- bionic-unit-tests-cts \
+ bionic-unit-tests-cts
cts_ui_tests := \
CtsUiAutomatorTests
cts_device_jars := \
- CtsDeviceJank
+ CtsDeviceJank \
+ CtsPrintInstrument
+
+cts_device_executables := \
+ print-instrument
# All the files that will end up under the repository/testcases
# directory of the final CTS distribution.
@@ -153,7 +158,8 @@
$(call cts-get-package-paths,$(cts_test_packages)) \
$(call cts-get-native-paths,$(cts_native_exes)) \
$(call cts-get-ui-lib-paths,$(cts_ui_tests)) \
- $(call cts-get-ui-lib-paths,$(cts_device_jars))
+ $(call cts-get-ui-lib-paths,$(cts_device_jars)) \
+ $(call cts-get-executable-paths,$(cts_device_executables))
# All the XMLs that will end up under the repository/testcases
# and that need to be created before making the final CTS distribution.
@@ -162,6 +168,5 @@
$(call cts-get-test-xmls,$(cts_native_exes)) \
$(call cts-get-test-xmls,$(cts_ui_tests))
-
# The following files will be placed in the tools directory of the CTS distribution
CTS_TOOLS_LIST :=
\ No newline at end of file
diff --git a/libs/testserver/src/android/webkit/cts/CtsTestServer.java b/libs/testserver/src/android/webkit/cts/CtsTestServer.java
index e4ac46e..a99459a 100644
--- a/libs/testserver/src/android/webkit/cts/CtsTestServer.java
+++ b/libs/testserver/src/android/webkit/cts/CtsTestServer.java
@@ -84,6 +84,7 @@
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSession;
import javax.net.ssl.X509TrustManager;
@@ -124,6 +125,13 @@
public static final String MESSAGE_403 = "403 forbidden";
public static final String MESSAGE_404 = "404 not found";
+ public enum SslMode {
+ INSECURE,
+ NO_CLIENT_AUTH,
+ WANTS_CLIENT_AUTH,
+ NEEDS_CLIENT_AUTH,
+ }
+
private static Hashtable<Integer, String> sReasons;
private ServerThread mServerThread;
@@ -131,7 +139,7 @@
private AssetManager mAssets;
private Context mContext;
private Resources mResources;
- private boolean mSsl;
+ private SslMode mSsl;
private MimeTypeMap mMap;
private Vector<String> mQueries;
private ArrayList<HttpEntity> mRequestEntities;
@@ -166,19 +174,30 @@
* @throws Exception
*/
public CtsTestServer(Context context, boolean ssl) throws Exception {
+ this(context, ssl ? SslMode.NO_CLIENT_AUTH : SslMode.INSECURE);
+ }
+
+ /**
+ * Create and start a local HTTP server instance.
+ * @param context The application context to use for fetching assets.
+ * @param sslMode Whether to use SSL, and if so, what client auth (if any) to use.
+ * @throws Exception
+ */
+ public CtsTestServer(Context context, SslMode sslMode) throws Exception {
mContext = context;
mAssets = mContext.getAssets();
mResources = mContext.getResources();
- mSsl = ssl;
+ mSsl = sslMode;
mRequestEntities = new ArrayList<HttpEntity>();
mMap = MimeTypeMap.getSingleton();
mQueries = new Vector<String>();
mServerThread = new ServerThread(this, mSsl);
- if (mSsl) {
- mServerUri = "https://localhost:" + mServerThread.mSocket.getLocalPort();
+ if (mSsl == SslMode.INSECURE) {
+ mServerUri = "http:";
} else {
- mServerUri = "http://localhost:" + mServerThread.mSocket.getLocalPort();
+ mServerUri = "https:";
}
+ mServerUri += "//localhost:" + mServerThread.mSocket.getLocalPort();
mServerThread.start();
}
@@ -217,7 +236,9 @@
private URLConnection openConnection(URL url)
throws IOException, NoSuchAlgorithmException, KeyManagementException {
- if (mSsl) {
+ if (mSsl == SslMode.INSECURE) {
+ return url.openConnection();
+ } else {
// Install hostname verifiers and trust managers that don't do
// anything in order to get around the client not trusting
// the test server due to a lack of certificates.
@@ -226,13 +247,14 @@
connection.setHostnameVerifier(new CtsHostnameVerifier());
SSLContext context = SSLContext.getInstance("TLS");
- CtsTrustManager trustManager = new CtsTrustManager();
- context.init(null, new CtsTrustManager[] {trustManager}, null);
+ try {
+ context.init(ServerThread.getKeyManagers(), getTrustManagers(), null);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
connection.setSSLSocketFactory(context.getSocketFactory());
return connection;
- } else {
- return url.openConnection();
}
}
@@ -244,7 +266,7 @@
*/
private static class CtsTrustManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] chain, String authType) {
- // Trust the CtSTestServer...
+ // Trust the CtSTestServer's client...
}
public void checkServerTrusted(X509Certificate[] chain, String authType) {
@@ -257,6 +279,13 @@
}
/**
+ * @returns a trust manager array configured to permit any trust decision.
+ */
+ private static CtsTrustManager[] getTrustManagers() {
+ return new CtsTrustManager[] { new CtsTrustManager() };
+ }
+
+ /**
* {@link HostnameVerifier} that verifies everybody. This permits
* the client to trust the web server and call
* {@link CtsTestServer#shutdown()}.
@@ -541,6 +570,8 @@
response = createResponse(HttpStatus.SC_OK);
response.setEntity(entity);
response.addHeader("Content-Disposition", "attachment; filename=test.bin");
+ response.addHeader("Content-Type", mimeType);
+ response.addHeader("Content-Length", "" + length);
} else {
// fall through, return 404 at the end
}
@@ -767,7 +798,7 @@
private static class ServerThread extends Thread {
private CtsTestServer mServer;
private ServerSocket mSocket;
- private boolean mIsSsl;
+ private SslMode mSsl;
private boolean mIsCancelled;
private SSLContext mSslContext;
private ExecutorService mExecutorService = Executors.newFixedThreadPool(20);
@@ -802,13 +833,13 @@
"1gaEjsC/0wGmmBDg1dTDH+F1p9TInzr3EFuYD0YiQ7YlAHq3cPuyGoLXJ5dXYuSBfhDXJSeddUkl" +
"k1ufZyOOcskeInQge7jzaRfmKg3U94r+spMEvb0AzDQVOKvjjo1ivxMSgFRZaDb/4qw=";
- private String PASSWORD = "android";
+ private static final String PASSWORD = "android";
/**
* Loads a keystore from a base64-encoded String. Returns the KeyManager[]
* for the result.
*/
- private KeyManager[] getKeyManagers() throws Exception {
+ private static KeyManager[] getKeyManagers() throws Exception {
byte[] bytes = Base64.decode(SERVER_KEYS_BKS.getBytes());
InputStream inputStream = new ByteArrayInputStream(bytes);
@@ -824,19 +855,24 @@
}
- public ServerThread(CtsTestServer server, boolean ssl) throws Exception {
+ public ServerThread(CtsTestServer server, SslMode sslMode) throws Exception {
super("ServerThread");
mServer = server;
- mIsSsl = ssl;
+ mSsl = sslMode;
int retry = 3;
while (true) {
try {
- if (mIsSsl) {
- mSslContext = SSLContext.getInstance("TLS");
- mSslContext.init(getKeyManagers(), null, null);
- mSocket = mSslContext.getServerSocketFactory().createServerSocket(0);
- } else {
+ if (mSsl == SslMode.INSECURE) {
mSocket = new ServerSocket(0);
+ } else { // Use SSL
+ mSslContext = SSLContext.getInstance("TLS");
+ mSslContext.init(getKeyManagers(), getTrustManagers(), null);
+ mSocket = mSslContext.getServerSocketFactory().createServerSocket(0);
+ if (mSsl == SslMode.WANTS_CLIENT_AUTH) {
+ ((SSLServerSocket) mSocket).setWantClientAuth(true);
+ } else if (mSsl == SslMode.NEEDS_CLIENT_AUTH) {
+ ((SSLServerSocket) mSocket).setNeedClientAuth(true);
+ }
}
return;
} catch (IOException e) {
diff --git a/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/primitive/GLPrimitiveBenchmark.java b/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/primitive/GLPrimitiveBenchmark.java
index 6c2c87d..c177129 100644
--- a/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/primitive/GLPrimitiveBenchmark.java
+++ b/suite/cts/deviceTests/opengl/src/com/android/cts/opengl/primitive/GLPrimitiveBenchmark.java
@@ -118,9 +118,8 @@
intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_ITERATIONS, numIterations);
intent.putExtra(GLActivityIntentKeys.INTENT_EXTRA_TIMEOUT, timeout);
- GLPrimitiveActivity activity = null;
setActivityIntent(intent);
- activity = getActivity();
+ GLPrimitiveActivity activity = getActivity();
if (activity != null) {
activity.waitForCompletion();
double[] fpsValues = activity.mFpsValues;
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index b65ded0..cc5832c 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -583,6 +583,12 @@
android:configChanges="keyboardHidden|orientation|screenSize">
</activity>
+ <activity android:name="android.hardware.camera2.cts.Camera2SurfaceViewStubActivity"
+ android:label="Camera2StubActivity"
+ android:screenOrientation="landscape"
+ android:configChanges="keyboardHidden|orientation|screenSize">
+ </activity>
+
<activity android:name="android.view.inputmethod.cts.InputMethodStubActivity"
android:label="InputMethodStubActivity">
<intent-filter>
diff --git a/tests/SignatureTest/Android.mk b/tests/SignatureTest/Android.mk
index 209e78a..696f99e 100644
--- a/tests/SignatureTest/Android.mk
+++ b/tests/SignatureTest/Android.mk
@@ -44,8 +44,6 @@
include $(BUILD_CTS_PACKAGE)
-$(info $(call local-intermediates-dir))
-
generated_res_stamp := $(intermediates.COMMON)/genres.stamp
api_ver_file := $(intermediates.COMMON)/api_ver_is_$(CTS_API_VERSION)
diff --git a/tests/SignatureTest/src/android/tests/sigtest/JDiffClassDescription.java b/tests/SignatureTest/src/android/tests/sigtest/JDiffClassDescription.java
index c51c6c3..36360d6 100644
--- a/tests/SignatureTest/src/android/tests/sigtest/JDiffClassDescription.java
+++ b/tests/SignatureTest/src/android/tests/sigtest/JDiffClassDescription.java
@@ -832,19 +832,14 @@
// Nothing to check if it doesn't extend anything.
if (mExtendedClass != null) {
Class<?> superClass = mClass.getSuperclass();
- if (superClass == null) {
- // API indicates superclass, reflection doesn't.
- return false;
- }
- if (superClass.getCanonicalName().equals(mExtendedClass)) {
- return true;
+ while (superClass != null) {
+ if (superClass.getCanonicalName().equals(mExtendedClass)) {
+ return true;
+ }
+ superClass = superClass.getSuperclass();
}
-
- if (mAbsoluteClassName.equals("android.hardware.SensorManager")) {
- // FIXME: Please see Issue 1496822 for more information
- return true;
- }
+ // Couldn't find a matching superclass.
return false;
}
return true;
diff --git a/tests/accessibility/AndroidManifest.xml b/tests/accessibility/AndroidManifest.xml
index 0d18cef..dde1de8 100644
--- a/tests/accessibility/AndroidManifest.xml
+++ b/tests/accessibility/AndroidManifest.xml
@@ -19,8 +19,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.view.accessibility.services">
- <uses-permission android:name="android.permission.CAN_REQUEST_TOUCH_EXPLORATION_MODE"/>
-
<application>
<service android:name=".SpeakingAccessibilityService"
diff --git a/tests/assets/webkit/iframe_blank_tag.html b/tests/assets/webkit/iframe_blank_tag.html
index 55ff410..fbc6dc6 100644
--- a/tests/assets/webkit/iframe_blank_tag.html
+++ b/tests/assets/webkit/iframe_blank_tag.html
@@ -16,7 +16,7 @@
<!DOCTYPE html>
<html>
<head>
- <script type='text/javascript'> window.open('test_hello_world.html'); </script>
+ <script type='text/javascript'> window.open('page_with_link.html'); </script>
</head>
</html>
diff --git a/tests/assets/webkit/page_with_link.html b/tests/assets/webkit/page_with_link.html
new file mode 100644
index 0000000..50fb78a
--- /dev/null
+++ b/tests/assets/webkit/page_with_link.html
@@ -0,0 +1,20 @@
+<!-- Copyright (C) 2013 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.
+-->
+
+<html>
+ <body>
+ <a href="http://foo.com" id="link">a link</a>
+ </body>
+</html>
diff --git a/tests/core/libcore/com/Android.mk b/tests/core/libcore/com/Android.mk
index 02dc3de..db08dbd 100644
--- a/tests/core/libcore/com/Android.mk
+++ b/tests/core/libcore/com/Android.mk
@@ -14,10 +14,6 @@
LOCAL_PATH:= $(call my-dir)
-ifeq ($(BUILD_CTSCORE_PACKAGE),)
- $(error BUILD_CTSCORE_PACKAGE must be defined)
-endif
-
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.com
LOCAL_STATIC_JAVA_LIBRARIES := core-tests
diff --git a/tests/core/libcore/dalvik/Android.mk b/tests/core/libcore/dalvik/Android.mk
index 7b77a75..42d14f3 100644
--- a/tests/core/libcore/dalvik/Android.mk
+++ b/tests/core/libcore/dalvik/Android.mk
@@ -14,10 +14,6 @@
LOCAL_PATH:= $(call my-dir)
-ifeq ($(BUILD_CTSCORE_PACKAGE),)
- $(error BUILD_CTSCORE_PACKAGE must be defined)
-endif
-
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.dalvik
LOCAL_STATIC_JAVA_LIBRARIES := core-tests
diff --git a/tests/core/libcore/harmony_annotation/Android.mk b/tests/core/libcore/harmony_annotation/Android.mk
new file mode 100644
index 0000000..e9f716e
--- /dev/null
+++ b/tests/core/libcore/harmony_annotation/Android.mk
@@ -0,0 +1,24 @@
+# Copyright (C) 2012 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)
+
+ifeq ($(BUILD_CTSCORE_PACKAGE),)
+ $(error BUILD_CTSCORE_PACKAGE must be defined)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.harmony_annotation
+LOCAL_STATIC_JAVA_LIBRARIES := core-tests
+include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/libcore/harmony_annotation/AndroidManifest.xml b/tests/core/libcore/harmony_annotation/AndroidManifest.xml
new file mode 100644
index 0000000..0c59b1b
--- /dev/null
+++ b/tests/core/libcore/harmony_annotation/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2012 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="android.core.tests.libcore.package.harmony_annotation">
+ <uses-permission android:name="android.permission.INTERNET" />
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationCtsTestRunner"
+ android:targetPackage="android.core.tests.runner"
+ android:label="cts framework tests"/>
+
+</manifest>
diff --git a/tests/core/libcore/harmony_beans/Android.mk b/tests/core/libcore/harmony_beans/Android.mk
new file mode 100644
index 0000000..2131ae0
--- /dev/null
+++ b/tests/core/libcore/harmony_beans/Android.mk
@@ -0,0 +1,24 @@
+# Copyright (C) 2012 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)
+
+ifeq ($(BUILD_CTSCORE_PACKAGE),)
+ $(error BUILD_CTSCORE_PACKAGE must be defined)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.harmony_beans
+LOCAL_STATIC_JAVA_LIBRARIES := apache-harmony-tests
+include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/libcore/harmony_beans/AndroidManifest.xml b/tests/core/libcore/harmony_beans/AndroidManifest.xml
new file mode 100644
index 0000000..b4932dd
--- /dev/null
+++ b/tests/core/libcore/harmony_beans/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2012 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="android.core.tests.libcore.package.harmony_beans">
+ <uses-permission android:name="android.permission.INTERNET" />
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationCtsTestRunner"
+ android:targetPackage="android.core.tests.runner"
+ android:label="cts framework tests"/>
+
+</manifest>
diff --git a/tests/core/libcore/harmony_java_io/Android.mk b/tests/core/libcore/harmony_java_io/Android.mk
new file mode 100644
index 0000000..a8d4fa0
--- /dev/null
+++ b/tests/core/libcore/harmony_java_io/Android.mk
@@ -0,0 +1,24 @@
+# Copyright (C) 2012 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)
+
+ifeq ($(BUILD_CTSCORE_PACKAGE),)
+ $(error BUILD_CTSCORE_PACKAGE must be defined)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.harmony_java_io
+LOCAL_STATIC_JAVA_LIBRARIES := core-tests
+include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/libcore/harmony_java_io/AndroidManifest.xml b/tests/core/libcore/harmony_java_io/AndroidManifest.xml
new file mode 100644
index 0000000..65d64ab
--- /dev/null
+++ b/tests/core/libcore/harmony_java_io/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2012 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="android.core.tests.libcore.package.harmony_java_io">
+ <uses-permission android:name="android.permission.INTERNET" />
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationCtsTestRunner"
+ android:targetPackage="android.core.tests.runner"
+ android:label="cts framework tests"/>
+
+</manifest>
diff --git a/tests/core/libcore/harmony_java_lang/Android.mk b/tests/core/libcore/harmony_java_lang/Android.mk
new file mode 100644
index 0000000..8b1bdff
--- /dev/null
+++ b/tests/core/libcore/harmony_java_lang/Android.mk
@@ -0,0 +1,24 @@
+# Copyright (C) 2012 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)
+
+ifeq ($(BUILD_CTSCORE_PACKAGE),)
+ $(error BUILD_CTSCORE_PACKAGE must be defined)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.harmony_java_lang
+LOCAL_STATIC_JAVA_LIBRARIES := core-tests
+include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/libcore/harmony_java_lang/AndroidManifest.xml b/tests/core/libcore/harmony_java_lang/AndroidManifest.xml
new file mode 100644
index 0000000..a5e499a
--- /dev/null
+++ b/tests/core/libcore/harmony_java_lang/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2012 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="android.core.tests.libcore.package.harmony_java_lang">
+ <uses-permission android:name="android.permission.INTERNET" />
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationCtsTestRunner"
+ android:targetPackage="android.core.tests.runner"
+ android:label="cts framework tests"/>
+
+</manifest>
diff --git a/tests/core/libcore/harmony_java_math/Android.mk b/tests/core/libcore/harmony_java_math/Android.mk
new file mode 100644
index 0000000..8310743
--- /dev/null
+++ b/tests/core/libcore/harmony_java_math/Android.mk
@@ -0,0 +1,24 @@
+# Copyright (C) 2012 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)
+
+ifeq ($(BUILD_CTSCORE_PACKAGE),)
+ $(error BUILD_CTSCORE_PACKAGE must be defined)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.harmony_java_math
+LOCAL_STATIC_JAVA_LIBRARIES := core-tests
+include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/libcore/harmony_java_math/AndroidManifest.xml b/tests/core/libcore/harmony_java_math/AndroidManifest.xml
new file mode 100644
index 0000000..f8cd224
--- /dev/null
+++ b/tests/core/libcore/harmony_java_math/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2012 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="android.core.tests.libcore.package.harmony_java_math">
+ <uses-permission android:name="android.permission.INTERNET" />
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationCtsTestRunner"
+ android:targetPackage="android.core.tests.runner"
+ android:label="cts framework tests"/>
+
+</manifest>
diff --git a/tests/core/libcore/harmony_java_net/Android.mk b/tests/core/libcore/harmony_java_net/Android.mk
new file mode 100644
index 0000000..7917bcc
--- /dev/null
+++ b/tests/core/libcore/harmony_java_net/Android.mk
@@ -0,0 +1,24 @@
+# Copyright (C) 2012 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)
+
+ifeq ($(BUILD_CTSCORE_PACKAGE),)
+ $(error BUILD_CTSCORE_PACKAGE must be defined)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.harmony_java_net
+LOCAL_STATIC_JAVA_LIBRARIES := core-tests
+include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/libcore/harmony_java_net/AndroidManifest.xml b/tests/core/libcore/harmony_java_net/AndroidManifest.xml
new file mode 100644
index 0000000..3c9fd63
--- /dev/null
+++ b/tests/core/libcore/harmony_java_net/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2012 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="android.core.tests.libcore.package.harmony_java_net">
+ <uses-permission android:name="android.permission.INTERNET" />
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationCtsTestRunner"
+ android:targetPackage="android.core.tests.runner"
+ android:label="cts framework tests"/>
+
+</manifest>
diff --git a/tests/core/libcore/harmony_java_nio/Android.mk b/tests/core/libcore/harmony_java_nio/Android.mk
new file mode 100644
index 0000000..2c6f673
--- /dev/null
+++ b/tests/core/libcore/harmony_java_nio/Android.mk
@@ -0,0 +1,24 @@
+# Copyright (C) 2012 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)
+
+ifeq ($(BUILD_CTSCORE_PACKAGE),)
+ $(error BUILD_CTSCORE_PACKAGE must be defined)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.harmony_java_nio
+LOCAL_STATIC_JAVA_LIBRARIES := core-tests
+include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/libcore/harmony_java_nio/AndroidManifest.xml b/tests/core/libcore/harmony_java_nio/AndroidManifest.xml
new file mode 100644
index 0000000..27166d4
--- /dev/null
+++ b/tests/core/libcore/harmony_java_nio/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2012 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="android.core.tests.libcore.package.harmony_java_nio">
+ <uses-permission android:name="android.permission.INTERNET" />
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationCtsTestRunner"
+ android:targetPackage="android.core.tests.runner"
+ android:label="cts framework tests"/>
+
+</manifest>
diff --git a/tests/core/libcore/harmony_java_text/Android.mk b/tests/core/libcore/harmony_java_text/Android.mk
new file mode 100644
index 0000000..ecd1574
--- /dev/null
+++ b/tests/core/libcore/harmony_java_text/Android.mk
@@ -0,0 +1,24 @@
+# Copyright (C) 2012 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)
+
+ifeq ($(BUILD_CTSCORE_PACKAGE),)
+ $(error BUILD_CTSCORE_PACKAGE must be defined)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.harmony_java_text
+LOCAL_STATIC_JAVA_LIBRARIES := core-tests
+include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/libcore/harmony_java_text/AndroidManifest.xml b/tests/core/libcore/harmony_java_text/AndroidManifest.xml
new file mode 100644
index 0000000..0b6beed
--- /dev/null
+++ b/tests/core/libcore/harmony_java_text/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2012 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="android.core.tests.libcore.package.harmony_java_text">
+ <uses-permission android:name="android.permission.INTERNET" />
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationCtsTestRunner"
+ android:targetPackage="android.core.tests.runner"
+ android:label="cts framework tests"/>
+
+</manifest>
diff --git a/tests/core/libcore/harmony_java_util/Android.mk b/tests/core/libcore/harmony_java_util/Android.mk
new file mode 100644
index 0000000..6d7bded
--- /dev/null
+++ b/tests/core/libcore/harmony_java_util/Android.mk
@@ -0,0 +1,24 @@
+# Copyright (C) 2012 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)
+
+ifeq ($(BUILD_CTSCORE_PACKAGE),)
+ $(error BUILD_CTSCORE_PACKAGE must be defined)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.harmony_java_util
+LOCAL_STATIC_JAVA_LIBRARIES := core-tests
+include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/libcore/harmony_java_util/AndroidManifest.xml b/tests/core/libcore/harmony_java_util/AndroidManifest.xml
new file mode 100644
index 0000000..72fa3ef
--- /dev/null
+++ b/tests/core/libcore/harmony_java_util/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2012 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="android.core.tests.libcore.package.harmony_java_util">
+ <uses-permission android:name="android.permission.INTERNET" />
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationCtsTestRunner"
+ android:targetPackage="android.core.tests.runner"
+ android:label="cts framework tests"/>
+
+</manifest>
diff --git a/tests/core/libcore/harmony_javax_security/Android.mk b/tests/core/libcore/harmony_javax_security/Android.mk
new file mode 100644
index 0000000..011940d
--- /dev/null
+++ b/tests/core/libcore/harmony_javax_security/Android.mk
@@ -0,0 +1,24 @@
+# Copyright (C) 2012 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)
+
+ifeq ($(BUILD_CTSCORE_PACKAGE),)
+ $(error BUILD_CTSCORE_PACKAGE must be defined)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.harmony_javax_security
+LOCAL_STATIC_JAVA_LIBRARIES := core-tests
+include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/libcore/harmony_javax_security/AndroidManifest.xml b/tests/core/libcore/harmony_javax_security/AndroidManifest.xml
new file mode 100644
index 0000000..b7b35f2
--- /dev/null
+++ b/tests/core/libcore/harmony_javax_security/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2012 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="android.core.tests.libcore.package.harmony_javax_security">
+ <uses-permission android:name="android.permission.INTERNET" />
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationCtsTestRunner"
+ android:targetPackage="android.core.tests.runner"
+ android:label="cts framework tests"/>
+
+</manifest>
diff --git a/tests/core/libcore/harmony_logging/Android.mk b/tests/core/libcore/harmony_logging/Android.mk
new file mode 100644
index 0000000..2ec10f1
--- /dev/null
+++ b/tests/core/libcore/harmony_logging/Android.mk
@@ -0,0 +1,24 @@
+# Copyright (C) 2012 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)
+
+ifeq ($(BUILD_CTSCORE_PACKAGE),)
+ $(error BUILD_CTSCORE_PACKAGE must be defined)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.harmony_logging
+LOCAL_STATIC_JAVA_LIBRARIES := apache-harmony-tests
+include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/libcore/harmony_logging/AndroidManifest.xml b/tests/core/libcore/harmony_logging/AndroidManifest.xml
new file mode 100644
index 0000000..94ee60e
--- /dev/null
+++ b/tests/core/libcore/harmony_logging/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2012 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="android.core.tests.libcore.package.harmony_logging">
+ <uses-permission android:name="android.permission.INTERNET" />
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationCtsTestRunner"
+ android:targetPackage="android.core.tests.runner"
+ android:label="cts framework tests"/>
+
+</manifest>
diff --git a/tests/core/libcore/harmony_prefs/Android.mk b/tests/core/libcore/harmony_prefs/Android.mk
new file mode 100644
index 0000000..92b0c7d
--- /dev/null
+++ b/tests/core/libcore/harmony_prefs/Android.mk
@@ -0,0 +1,24 @@
+# Copyright (C) 2012 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)
+
+ifeq ($(BUILD_CTSCORE_PACKAGE),)
+ $(error BUILD_CTSCORE_PACKAGE must be defined)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.harmony_prefs
+LOCAL_STATIC_JAVA_LIBRARIES := apache-harmony-tests
+include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/libcore/harmony_prefs/AndroidManifest.xml b/tests/core/libcore/harmony_prefs/AndroidManifest.xml
new file mode 100644
index 0000000..f8fdea2
--- /dev/null
+++ b/tests/core/libcore/harmony_prefs/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2012 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="android.core.tests.libcore.package.harmony_prefs">
+ <uses-permission android:name="android.permission.INTERNET" />
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationCtsTestRunner"
+ android:targetPackage="android.core.tests.runner"
+ android:label="cts framework tests"/>
+
+</manifest>
diff --git a/tests/core/libcore/harmony_sql/Android.mk b/tests/core/libcore/harmony_sql/Android.mk
new file mode 100644
index 0000000..b1df215
--- /dev/null
+++ b/tests/core/libcore/harmony_sql/Android.mk
@@ -0,0 +1,24 @@
+# Copyright (C) 2012 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)
+
+ifeq ($(BUILD_CTSCORE_PACKAGE),)
+ $(error BUILD_CTSCORE_PACKAGE must be defined)
+endif
+
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.harmony_sql
+LOCAL_STATIC_JAVA_LIBRARIES := apache-harmony-tests
+include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/libcore/harmony_sql/AndroidManifest.xml b/tests/core/libcore/harmony_sql/AndroidManifest.xml
new file mode 100644
index 0000000..c6c31b2
--- /dev/null
+++ b/tests/core/libcore/harmony_sql/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2012 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="android.core.tests.libcore.package.harmony_sql">
+ <uses-permission android:name="android.permission.INTERNET" />
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationCtsTestRunner"
+ android:targetPackage="android.core.tests.runner"
+ android:label="cts framework tests"/>
+
+</manifest>
diff --git a/tests/core/libcore/jsr166/Android.mk b/tests/core/libcore/jsr166/Android.mk
new file mode 100644
index 0000000..3f9871e
--- /dev/null
+++ b/tests/core/libcore/jsr166/Android.mk
@@ -0,0 +1,20 @@
+# Copyright (C) 2013 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)
+LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.jsr166
+LOCAL_STATIC_JAVA_LIBRARIES := jsr166-tests
+include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/libcore/jsr166/AndroidManifest.xml b/tests/core/libcore/jsr166/AndroidManifest.xml
new file mode 100644
index 0000000..3a0150e
--- /dev/null
+++ b/tests/core/libcore/jsr166/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2013 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="android.core.tests.libcore.package.jsr166">
+ <uses-permission android:name="android.permission.INTERNET" />
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationCtsTestRunner"
+ android:targetPackage="android.core.tests.runner"
+ android:label="cts framework tests"/>
+
+</manifest>
diff --git a/tests/core/libcore/libcore/Android.mk b/tests/core/libcore/libcore/Android.mk
index 382b386..a86d2c0 100644
--- a/tests/core/libcore/libcore/Android.mk
+++ b/tests/core/libcore/libcore/Android.mk
@@ -14,10 +14,6 @@
LOCAL_PATH:= $(call my-dir)
-ifeq ($(BUILD_CTSCORE_PACKAGE),)
- $(error BUILD_CTSCORE_PACKAGE must be defined)
-endif
-
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.libcore
LOCAL_STATIC_JAVA_LIBRARIES := core-tests
diff --git a/tests/core/libcore/org/Android.mk b/tests/core/libcore/org/Android.mk
index d7a96b3..0f3f0ca 100644
--- a/tests/core/libcore/org/Android.mk
+++ b/tests/core/libcore/org/Android.mk
@@ -14,10 +14,6 @@
LOCAL_PATH:= $(call my-dir)
-ifeq ($(BUILD_CTSCORE_PACKAGE),)
- $(error BUILD_CTSCORE_PACKAGE must be defined)
-endif
-
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.org
LOCAL_STATIC_JAVA_LIBRARIES := core-tests
diff --git a/tests/core/libcore/sun/Android.mk b/tests/core/libcore/sun/Android.mk
index 44d3d70..ed6d2c7 100644
--- a/tests/core/libcore/sun/Android.mk
+++ b/tests/core/libcore/sun/Android.mk
@@ -14,10 +14,6 @@
LOCAL_PATH:= $(call my-dir)
-ifeq ($(BUILD_CTSCORE_PACKAGE),)
- $(error BUILD_CTSCORE_PACKAGE must be defined)
-endif
-
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.sun
LOCAL_STATIC_JAVA_LIBRARIES := core-tests
diff --git a/tests/core/libcore/tests/Android.mk b/tests/core/libcore/tests/Android.mk
index bfd235f..54ffd31 100644
--- a/tests/core/libcore/tests/Android.mk
+++ b/tests/core/libcore/tests/Android.mk
@@ -14,10 +14,6 @@
LOCAL_PATH:= $(call my-dir)
-ifeq ($(BUILD_CTSCORE_PACKAGE),)
- $(error BUILD_CTSCORE_PACKAGE must be defined)
-endif
-
include $(CLEAR_VARS)
LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.tests
LOCAL_STATIC_JAVA_LIBRARIES := core-tests
diff --git a/tests/plans/CTS-flaky.xml b/tests/plans/CTS-flaky.xml
index ee64ba0..30304b4 100644
--- a/tests/plans/CTS-flaky.xml
+++ b/tests/plans/CTS-flaky.xml
@@ -8,5 +8,4 @@
<Entry uri="android.provider" exclude="android.provider.cts.ContactsContract_CommonDataKinds_EventTest#testGetTypeLabel;android.provider.cts.MediaStore_Audio_Genres_MembersTest#testStoreAudioGenresMembersInternal;android.provider.cts.ContactsContract_DataTest#testDataInsert_updatesContactLastUpdatedTimestamp;android.provider.cts.ContactsContract_CommonDataKinds_EmailTest#testGetTypeLabel;android.provider.cts.Settings_NameValueTableTest#testPutString;android.provider.cts.CalendarTest#testCalendarEntityQuery;android.provider.cts.ContactsContract_DataUsageTest#testSingleDataUsageFeedback_incrementsCorrectDataItems;android.provider.cts.BrowserTest#testSendString;android.provider.cts.MediaStore_Video_MediaTest#testStoreVideoMediaInternal;android.provider.cts.UserDictionary_WordsTest#testAddWord_deprecated;android.provider.cts.MediaStoreIntentsTest#testAndroidTestCaseSetupProperly;android.provider.cts.ContactsContract_DeletedContacts#testQuerySinceTimestamp;android.provider.cts.BrowserTest#testRequestAllIcons;android.provider.cts.ContactsContract_CommonDataKinds_EmailTest#testAndroidTestCaseSetupProperly;android.provider.cts.CalendarTest#testReminders;android.provider.cts.MediaStore_Audio_ArtistsTest#testStoreAudioArtistsExternal;android.provider.cts.ContactsContractIntentsTest#testViewContactDir;android.provider.cts.CalendarTest#testBulkUpdate;android.provider.cts.ContactsContract_PhotoTest#testAddPhoto;android.provider.cts.Settings_NameValueTableTest#testAndroidTestCaseSetupProperly;android.provider.cts.ContactsProvider2_AccountRemovalTest#testAccountRemovalWithMergedContact_hasDeleteLogsForContacts;android.provider.cts.ContactsContract_PhotoTest#testAddEmptyPhoto;android.provider.cts.Settings_SecureTest#testGetPutFloat;android.provider.cts.MediaStore_Images_MediaTest#testGetContentUri;android.provider.cts.ContactsContract_DeletedContacts#testDelete_isUnsupported;android.provider.cts.CalendarTest#testCalendarCreationAndDeletion;android.provider.cts.BrowserTest#testBookmarksTable;android.provider.cts.Settings_SecureTest#testGetUriFor;android.provider.cts.ContactsContract_StatusUpdatesTest#testGetPresenceIconresourceId;android.provider.cts.MediaStore_Audio_Playlists_MembersTest#testStoreAudioPlaylistsMembersInternal;android.provider.cts.ContactsContract_CommonDataKinds_EventTest#testAndroidTestCaseSetupProperly;android.provider.cts.Contacts_PhonesTest#testGetDisplayLabel;android.provider.cts.ContactsContract_DeletedContacts#testInsert_isUnsupported;android.provider.cts.MediaStore_Audio_AlbumsTest#testStoreAudioAlbumsExternal;android.provider.cts.ContactsContract_DeletedContacts#testAndroidTestCaseSetupProperly;android.provider.cts.BrowserTest#testGetAllVisitedUrls;android.provider.cts.Contacts_ContactMethodsTest#testEncodeAndDecodeProtocol;android.provider.cts.ContactsContract_DeletedContacts#testQueryAll;android.provider.cts.MediaStore_Audio_MediaTest#testStoreAudioMediaInternal;android.provider.cts.ContactsContract_RawContactsTest#testRawContactPsuedoDelete_hasDeleteLogForContact;android.provider.cts.MediaStore_FilesTest#testAndroidTestCaseSetupProperly;android.provider.cts.MediaStore_Images_MediaTest#testStoreImagesMediaInternal;android.provider.cts.MediaStore_Audio_AlbumsTest#testAlbumArt;android.provider.cts.ContactsContract_ContactsTest#testLookupUri;android.provider.cts.MediaStoreIntentsTest#testPickVideoDir;android.provider.cts.MediaStore_Images_MediaTest#testInsertImageWithBitmap;android.provider.cts.MediaStoreIntentsTest#testViewAudioFile;android.provider.cts.MediaStore_Audio_Genres_MembersTest#testStoreAudioGenresMembersExternal;android.provider.cts.ContactsContract_CommonDataKinds_StructuredPostalTest#testAndroidTestCaseSetupProperly;android.provider.cts.CalendarTest#testInstanceSearch;android.provider.cts.VoicemailContractTest#testStatusTablePermissions;android.provider.cts.ContactsContract_CommonDataKinds_OrganizationTest#testAndroidTestCaseSetupProperly;android.provider.cts.SettingsTest#testAndroidTestCaseSetupProperly;android.provider.cts.MediaStore_Audio_PlaylistsTest#testStoreAudioPlaylistsInternal;android.provider.cts.ContactsContract_DumpFileProviderTest#testQuery_worksWithValidFileName;android.provider.cts.Settings_SecureTest#testAndroidTestCaseSetupProperly;android.provider.cts.MediaStore_Video_MediaTest#testAndroidTestCaseSetupProperly;android.provider.cts.BrowserTest#testAccessHistory;android.provider.cts.ContactsContract_DataTest#testContactablesFilterByPhonePrefix_returnsCorrectDataRows;android.provider.cts.MediaStore_Images_ThumbnailsTest#testStoreImagesMediaInternal;android.provider.cts.ContactsTest#testCallsTable;android.provider.cts.CalendarTest#testEventCreationAndDeletion;android.provider.cts.VoicemailContractTest#testVoicemailTablePermissions;android.provider.cts.CalendarTest#testEventsUid2445;android.provider.cts.MediaStore_VideoTest#testQuery;android.provider.cts.CalendarTest#testDefaultProjections;android.provider.cts.MediaStoreIntentsTest#testViewVideoDir;android.provider.cts.MediaStore_FilesTest#testGetContentUri;android.provider.cts.ContactsContract_ContactsTest#testInsert_isUnsupported;android.provider.cts.ContactsContract_CommonDataKinds_PhoneTest#testGetTypeLabel;android.provider.cts.VoicemailContractTest#testVoicemailsTable;android.provider.cts.ContactsContract_CommonDataKinds_RelationTest#testGetTypeLabel;android.provider.cts.Settings_SystemTest#testGetDefaultValues;android.provider.cts.ContactsContract_RawContactsTest#testAndroidTestCaseSetupProperly;android.provider.cts.MediaStoreTest#testGetMediaScannerUri;android.provider.cts.ContactsContract_RawContactsTest#testRawContactDelete_removesRecord;android.provider.cts.Settings_SecureTest#testGetPutString;android.provider.cts.ContactsTest#testGroupMembershipTable;android.provider.cts.MediaStore_Audio_MediaTest#testGetContentUri;android.provider.cts.CalendarTest#testFullRecurrenceUpdate;android.provider.cts.MediaStore_FilesTest#testCaseSensitivity;android.provider.cts.MediaStore_Audio_AlbumsTest#testAndroidTestCaseSetupProperly;android.provider.cts.MediaStore_Audio_ArtistsTest#testStoreAudioArtistsInternal;android.provider.cts.ContactsContract_ContactsTest#testContactDelete_hasDeleteLog;android.provider.cts.ContactsContract_DataUsageTest#testMultiIdDataUsageFeedback_incrementsCorrectDataItems;android.provider.cts.CalendarTest#testSyncOnlyInsertEnforcement;android.provider.cts.VoicemailContractTest#testDataColumnUpdate_throwsIllegalArgumentException;android.provider.cts.CalendarTest#testColorWriteRequirements;android.provider.cts.CalendarTest#testWhenByDayQuery;android.provider.cts.ContactsContract_StreamItemsTest#testAndroidTestCaseSetupProperly;android.provider.cts.ContactsContract_CommonDataKinds_ImTest#testAndroidTestCaseSetupProperly;android.provider.cts.MediaStore_AudioTest#testKeyFor;android.provider.cts.ContactsContract_ContactsTest#testAndroidTestCaseSetupProperly;android.provider.cts.MediaStore_Images_ThumbnailsTest#testQueryInternalThumbnails;android.provider.cts.ContactsContract_DumpFileProviderTest#testOpenFileDescriptor_throwsErrorWithIllegalFileName;android.provider.cts.CalendarTest#testEventColors;android.provider.cts.SettingsTest#testBluetoothDevicesTable;android.provider.cts.ContactsContract_RawContactsTest#testRawContactUpdate_updatesContactUpdatedTimestamp;android.provider.cts.ContactsContract_CommonDataKinds_RelationTest#testAndroidTestCaseSetupProperly;android.provider.cts.MediaStoreTest#testGetVersion;android.provider.cts.MediaStore_Audio_GenresTest#testGetContentUri;android.provider.cts.ContactsContract_DataTest#testDataDelete_updatesContactLastUpdatedTimestamp;android.provider.cts.ContactsContract_CommonDataKinds_SipAddressTest#testGetTypeLabel;android.provider.cts.BrowserTest#testSaveBookmark;android.provider.cts.ContactsProvider2_AccountRemovalTest#testAndroidTestCaseSetupProperly;android.provider.cts.MediaStore_Video_MediaTest#testGetContentUri;android.provider.cts.CalendarTest#testExtendedProperties;android.provider.cts.Settings_SystemTest#testAndroidTestCaseSetupProperly;android.provider.cts.CalendarTest#testNonAdapterRecurrenceExceptions;android.provider.cts.CalendarTest#testOutOfOrderRecurrenceExceptions;android.provider.cts.CalendarTest#testConversionToRecurring;android.provider.cts.MediaStore_Audio_Playlists_MembersTest#testStoreAudioPlaylistsMembersExternal;android.provider.cts.CalendarTest#testMultiRuleRecurrence;android.provider.cts.MediaStoreIntentsTest#testPickAudioDir;android.provider.cts.MediaStore_Audio_GenresTest#testStoreAudioGenresExternal;android.provider.cts.MediaStoreIntentsTest#testViewVideoFile;android.provider.cts.ContactsProvider2_AccountRemovalTest#testAccountRemoval_deletesContacts;android.provider.cts.Contacts_ContactMethodsTest#testAndroidTestCaseSetupProperly;android.provider.cts.ContactsContract_GroupMembershipTest#testAddGroupMembershipWithGroupRowId;android.provider.cts.TelephonyProviderTest#testOpeningAnyFile;android.provider.cts.MediaStore_Audio_GenresTest#testGetContentUriForAudioId;android.provider.cts.ContactsContract_CommonDataKinds_PhoneTest#testAndroidTestCaseSetupProperly;android.provider.cts.Contacts_PeopleTest#testMarkAsContacted;android.provider.cts.MediaStore_FilesTest#testAccess;android.provider.cts.ContactsContract_CommonDataKinds_ImTest#testGetTypeLabel;android.provider.cts.SearchRecentSuggestionsTest#testSuggestionsTable;android.provider.cts.CalendarTest#testAttendees;android.provider.cts.SettingsTest#testAccessNonTable;android.provider.cts.MediaStoreIntentsTest#testPickImageDir;android.provider.cts.BrowserTest#testSearchesTable;android.provider.cts.Contacts_SettingsTest#testAccessSetting;android.provider.cts.ContactsContract_StreamItemPhotosTest#testContentPhotoUri;android.provider.cts.ContactsContract_DataTest#testGetLookupUriByDisplayName;android.provider.cts.ContactsContract_StatusUpdatesTest#testInsertStatus;android.provider.cts.MediaStore_Video_ThumbnailsTest#testGetContentUri;android.provider.cts.MediaStore_Audio_GenresTest#testStoreAudioGenresInternal;android.provider.cts.MediaStore_Images_MediaTest#testInsertImageWithImagePath;android.provider.cts.CalendarTest#testForwardRecurrenceExceptions;android.provider.cts.Settings_SecureTest#testUnknownSourcesOffByDefault;android.provider.cts.CalendarTest#testBadRequests;android.provider.cts.ContactsTest#testSettingsTable;android.provider.cts.VoicemailContractTest#testInsert_doesNotUpdateDataColumn;android.provider.cts.ContactsContract_RawContactsTest#testRawContactCreate_updatesContactUpdatedTimestamp;android.provider.cts.MediaStoreIntentsTest#testViewImageDir;android.provider.cts.ContactsContract_ContactsTest#testContactDelete_removesContactRecord;android.provider.cts.MediaStore_Images_ThumbnailsTest#testQueryExternalMiniThumbnails;android.provider.cts.ContactsContract_ContactsTest#testContactUpdate_updatesContactUpdatedTimestamp;android.provider.cts.Settings_SettingNotFoundExceptionTest#testAndroidTestCaseSetupProperly;android.provider.cts.ContactsContract_RawContactsTest#testGetLookupUriByDisplayName;android.provider.cts.BrowserTest#testAccessSearches;android.provider.cts.ContactsContract_CommonDataKinds_SipAddressTest#testAndroidTestCaseSetupProperly;android.provider.cts.ContactsContract_GroupMembershipTest#testAddGroupMembershipWithUnknownGroupSourceId;android.provider.cts.MediaStore_Audio_MediaTest#testStoreAudioMediaExternal;android.provider.cts.MediaStore_Audio_PlaylistsTest#testGetContentUri;android.provider.cts.ContactsTest#testGroupsTable;android.provider.cts.MediaStore_Audio_AlbumsTest#testGetContentUri;android.provider.cts.Settings_SystemTest#testGetUriFor;android.provider.cts.ContactsContract_StreamItemPhotosTest#testContentDirectoryUri;android.provider.cts.SearchRecentSuggestionsTest#testSearchRecentSuggestions;android.provider.cts.Contacts_ContactMethodsTest#testAddPostalLocation;android.provider.cts.MediaStore_Audio_Artists_AlbumsTest#testGetContentUri;android.provider.cts.SearchRecentSuggestionsTest#testConstructor;android.provider.cts.ContactsContract_ContactsTest#testMarkAsContacted;android.provider.cts.ContactsTest#testPeopleTable;android.provider.cts.CalendarTest#testCalendarColors;android.provider.cts.CalendarTest#testCalendarIsPrimary;android.provider.cts.ContactsContract_RawContactsTest#testRawContactDelete_hasDeleteLogForContact;android.provider.cts.Settings_SystemTest#testSystemSettings;android.provider.cts.CalendarTest#testRecurrence;android.provider.cts.ContactsContract_GroupMembershipTest#testAddGroupMembershipWithGroupSourceId;android.provider.cts.MediaStore_Audio_Genres_MembersTest#testGetContentUri;android.provider.cts.VoicemailContractTest#testStatusTable;android.provider.cts.ContactsContract_DataTest#testContactablesFilterByFirstName_returnsCorrectDataRows;android.provider.cts.Settings_NameValueTableTest#testGetUriFor;android.provider.cts.ContactsContract_DumpFileProviderTest#testQuery_throwsErrorWithIllegalFileName;android.provider.cts.ContactsTest#testContactMethodsTable;android.provider.cts.ContactsContractIntentsTest#testPickContactDir;android.provider.cts.MediaStore_Audio_AlbumsTest#testStoreAudioAlbumsInternal;android.provider.cts.Contacts_PeopleTest#testAddToGroup;android.provider.cts.ContactsContract_DataTest#testContactablesFilterByEmailPrefix_returnsCorrectDataRows;android.provider.cts.ContactsContract_StatusUpdatesTest#testGetPresencePrecedence;android.provider.cts.BrowserTest#testUpdateVisitedHistory;android.provider.cts.SettingsTest#testSecureTable;android.provider.cts.ContactsContract_StreamItemsTest#testContentUri;android.provider.cts.MediaStore_Audio_Artists_AlbumsTest#testStoreAudioArtistsAlbumsInternal;android.provider.cts.MediaStore_Video_ThumbnailsTest#testGetThumbnail;android.provider.cts.ContactsContractIntentsTest#testGetContentContactDir;android.provider.cts.SettingsTest#testSystemTable;android.provider.cts.CalendarTest#testEventUpdateAsApp;android.provider.cts.MediaStore_Images_MediaTest#testStoreImagesMediaExternal;android.provider.cts.CalendarTest#testEventsEntityQuery;android.provider.cts.ContactsContractIntentsTest#testAndroidTestCaseSetupProperly;android.provider.cts.CalendarTest#testSyncState;android.provider.cts.MediaStore_Video_ThumbnailsTest#testAndroidTestCaseSetupProperly;android.provider.cts.ContactsContract_DataTest#testGetLookupUriBySourceId;android.provider.cts.UserDictionary_WordsTest#testAndroidTestCaseSetupProperly;android.provider.cts.ContactsTest#testExtensionsTable;android.provider.cts.ContactsContract_DataTest#testContactablesUri;android.provider.cts.ContactsContract_CommonDataKinds_ImTest#testGetProtocolLabel;android.provider.cts.Settings_SettingNotFoundExceptionTest#testConstructor;android.provider.cts.CalendarTest#testEventsIsOrganizer;android.provider.cts.ContactsContract_StreamItemsTest#testContentDirectoryUri;android.provider.cts.Contacts_PeopleTest#testAccessPhotoData;android.provider.cts.UserDictionary_WordsTest#testAddWord;android.provider.cts.CalendarTest#testSingleRecurrenceExceptions;android.provider.cts.BrowserTest#testGetAllBookmarks;android.provider.cts.ContactsContract_RawContactsTest#testRawContactDelete_setsDeleteFlag;android.provider.cts.MediaStoreIntentsTest#testViewImageFile;android.provider.cts.Settings_SecureTest#testGetPutLong;android.provider.cts.ContactsContract_DataTest#testContactablesFilterByLastName_returnsCorrectDataRows;android.provider.cts.SearchRecentSuggestionsTest#testAndroidTestCaseSetupProperly;android.provider.cts.Contacts_PhonesTest#testGetDisplayLabelCharSequenceArray;android.provider.cts.SettingsTest#testUserDictionarySettingsExists;android.provider.cts.Contacts_OrganizationsTest#testGetDisplayLabel;android.provider.cts.Settings_SecureTest#testGetDefaultValues;android.provider.cts.ContactsContract_ContactsTest#testContactDelete_marksRawContactsForDeletion;android.provider.cts.ContactsTest#testPhotosTable;android.provider.cts.ContactsContract_ContactsTest#testContentUri;android.provider.cts.MediaStore_Audio_Artists_AlbumsTest#testStoreAudioArtistsAlbumsExternal;android.provider.cts.Contacts_PhonesTest#testAndroidTestCaseSetupProperly;android.provider.cts.ContactsProvider2_AccountRemovalTest#testAccountRemovalWithMergedContact_doesNotDeleteContactAndTimestampUpdated;android.provider.cts.ContactsTest#testOrganizationsTable;android.provider.cts.MediaStore_Audio_Playlists_MembersTest#testGetContentUri;android.provider.cts.MediaStore_Audio_PlaylistsTest#testStoreAudioPlaylistsExternal;android.provider.cts.Contacts_OrganizationsTest#testAndroidTestCaseSetupProperly;android.provider.cts.ContactsTest#testPhonesTable;android.provider.cts.Settings_SecureTest#testGetPutInt;android.provider.cts.ContactsContract_StatusUpdatesTest#testAndroidTestCaseSetupProperly;android.provider.cts.MediaStore_Audio_MediaTest#testGetContentUriForPath;android.provider.cts.CalendarTest#testCalendarUpdateAsApp;android.provider.cts.ContactsContract_DeletedContacts#testQueryByContactId;android.provider.cts.ContactsProvider2_AccountRemovalTest#testAccountRemoval_hasDeleteLogsForContacts;android.provider.cts.ContactsContract_StreamItemPhotosTest#testAndroidTestCaseSetupProperly;android.provider.cts.MediaStore_Audio_ArtistsTest#testGetContentUri;android.provider.cts.ContactsContract_DumpFileProviderTest#testAndroidTestCaseSetupProperly;android.provider.cts.ContactsContract_DataTest#testDataUpdate_updatesContactLastUpdatedTimestamp;android.provider.cts.ContactsProvider2_AccountRemovalTest#testAccountRemovalWithMergedContact_deletesContacts;android.provider.cts.ContactsContract_RawContactsTest#testGetLookupUriBySourceId;android.provider.cts.MediaStore_Images_ThumbnailsTest#testGetContentUri;android.provider.cts.ContactsContract_DumpFileProviderTest#testOpenFileDescriptor_worksWithValidFileName;android.provider.cts.ContactsContract_CommonDataKinds_StructuredPostalTest#testGetTypeLabel;android.provider.cts.ContactsContract_DataUsageTest#testAndroidTestCaseSetupProperly;android.provider.cts.Contacts_ContactMethodsTest#test;android.provider.cts.MediaStore_Video_MediaTest#testStoreVideoMediaExternal;android.provider.cts.ContactsContract_CommonDataKinds_OrganizationTest#testGetTypeLabel;android.provider.cts.MediaStore_Images_ThumbnailsTest#testStoreImagesMediaExternal;android.provider.cts.ContactsContract_DataTest#testContactablesFilter_doesNotExist_returnsCorrectDataRows;android.provider.cts.ContactsContract_DeletedContacts#testQuery_returnsProperColumns" />
<Entry uri="android.security" exclude="android.security.cts.KeystoreExploitTest#testAndroidTestCaseSetupProperly;android.security.cts.CharDeviceTest#testExynosKernelMemoryRead;android.security.cts.VoldExploitTest#testAndroidTestCaseSetupProperly;android.security.cts.LoadEffectLibraryTest#testLoadLibrary;android.security.cts.BrowserTest#testAndroidTestCaseSetupProperly;android.security.cts.LinuxRngTest#testDevUrandomMajorMinor;android.security.cts.ServicePermissionsTest#testDumpProtected;android.security.cts.BannedFilesTest#testNoSetuidTcpdump;android.security.cts.SqliteJournalLeakTest#testShm;android.security.cts.LinuxRngTest#testDevRandomMajorMinor;android.security.cts.ClonedSecureRandomTest#testCheckForDuplicateOutput;android.security.cts.BrowserTest#testBrowserPrivateDataAccess;android.security.cts.BrowserTest#testTabExhaustion;android.security.cts.KeystoreExploitTest#testKeystoreCrash;android.security.cts.SqliteJournalLeakTest#testJournal;android.security.cts.BannedFilesTest#testNoCmdClient;android.security.cts.BannedFilesTest#testNoSetuidIp;android.security.cts.BannedFilesTest#testNoSyncAgent;android.security.cts.BannedFilesTest#testNoInitRunIt;android.security.cts.ListeningPortsTest#testNoListeningLoopbackTcp6Ports;android.security.cts.KernelSettingsTest#testKptrRestrict;android.security.cts.AslrTest#testVaRandomize;android.security.cts.KernelSettingsTest#testMmapMinAddr;android.security.cts.CertificateTest#testBlockCertificates;android.security.cts.BrowserTest#testTabReuse;android.security.cts.KernelSettingsTest#testSELinuxEnforcing;android.security.cts.ListeningPortsTest#testNoListeningLoopbackUdp6Ports;android.security.cts.NativeCodeTest#testPerfEvent;android.security.cts.KernelSettingsTest#testSetuidDumpable;android.security.cts.PackageSignatureTest#testAndroidTestCaseSetupProperly;android.security.cts.ServicePermissionsTest#testAndroidTestCaseSetupProperly;android.security.cts.CertificateTest#testCertificates;android.security.cts.KernelSettingsTest#testNoConfigGz;android.security.cts.KernelSettingsTest#testDmesgRestrict;android.security.cts.ListeningPortsTest#testAndroidTestCaseSetupProperly;android.security.cts.SqliteJournalLeakTest#testAndroidTestCaseSetupProperly;android.security.cts.ListeningPortsTest#testNoRemotelyAccessibleListeningTcp6Ports;android.security.cts.ListeningPortsTest#testNoListeningLoopbackTcpPorts;android.security.cts.ClonedSecureRandomTest#testAndroidTestCaseSetupProperly;android.security.cts.VoldExploitTest#testTryCommandInjection;android.security.cts.VoldExploitTest#testZergRushCrash;android.security.cts.AslrTest#testOneExecutableIsPie;android.security.cts.VoldExploitTest#testTryToCrashVold;android.security.cts.ListeningPortsTest#testNoListeningLoopbackUdpPorts;android.security.cts.CertificateTest#testAndroidTestCaseSetupProperly;android.security.cts.SqliteJournalLeakTest#testWal;android.security.cts.ListeningPortsTest#testNoRemotelyAccessibleListeningTcpPorts;android.security.cts.CharDeviceTest#testExynosRootingVuln" />
<Entry uri="android.webkit" exclude="android.webkit.cts.WebViewTest#testDocumentHasImages;android.webkit.cts.WebViewTest#testScrollBarOverlay;android.webkit.cts.WebViewTest#testGoBackAndForward;android.webkit.cts.WebViewTest#testGetContentHeight;android.webkit.cts.WebChromeClientTest#testOnJsConfirm;android.webkit.cts.WebChromeClientTest#testOnProgressChanged;android.webkit.cts.WebViewTest#testAddJavascriptInterfaceNullObject;android.webkit.cts.WebViewTest#testConstructor;android.webkit.cts.WebViewTest#testInvokeZoomPicker;android.webkit.cts.WebSettingsTest#testAccessMinimumLogicalFontSize;android.webkit.cts.WebViewStartupTest#testCookieManagerBlockingUiThread;android.webkit.cts.WebViewTest#testInternals;android.webkit.cts.WebViewClientTest#testShouldOverrideUrlLoading;android.webkit.cts.GeolocationTest#testSimpleGeolocationRequestAcceptOnce;android.webkit.cts.WebSettingsTest#testDatabaseDisabled;android.webkit.cts.WebView_WebViewTransportTest#testAccessWebView;android.webkit.cts.WebSettingsTest#testAccessJavaScriptCanOpenWindowsAutomatically;android.webkit.cts.WebSettingsTest#testAppCacheEnabled;android.webkit.cts.WebSettingsTest#testAccessUserAgentString;android.webkit.cts.WebViewTest#testClearHistory;android.webkit.cts.WebSettingsTest#testAccessSerifFontFamily;android.webkit.cts.WebSettingsTest#testAccessLayoutAlgorithm;android.webkit.cts.WebSettingsTest#testAccessFantasyFontFamily;android.webkit.cts.WebViewTest#testAddJavascriptInterface;android.webkit.cts.WebSettingsTest#testAccessCacheMode;android.webkit.cts.WebViewTest#testDebugDump;android.webkit.cts.WebViewTest#testSslErrorProceedResponseNotReusedForDifferentHost;android.webkit.cts.WebSettingsTest#testLocalImageLoads;android.webkit.cts.WebViewTest#testSslErrorProceedResponseReusedForSameHost;android.webkit.cts.HttpAuthHandlerTest#testUseHttpAuthUsernamePassword;android.webkit.cts.WebViewTest#testSetLayoutParams;android.webkit.cts.WebViewTest#testAppInjectedXRequestedWithHeaderIsNotOverwritten;android.webkit.cts.WebSettingsTest#testAccessUseDoubleTree;android.webkit.cts.WebViewTest#testOnReceivedSslErrorCancel;android.webkit.cts.URLUtilTest#testIsHttpUrl;android.webkit.cts.DateSorterTest#testConstants;android.webkit.cts.WebSettingsTest#testAccessFixedFontFamily;android.webkit.cts.WebSettingsTest#testSetRenderPriority;android.webkit.cts.WebViewTest#testRemoveJavascriptInterface;android.webkit.cts.WebViewTest#testAndroidAssetAnchor;android.webkit.cts.WebViewTest#testOnReceivedSslError;android.webkit.cts.CookieTest#testEmptyValue;android.webkit.cts.WebViewTest#testPauseResumeTimers;android.webkit.cts.URLUtilTest#testIsContentUrl;android.webkit.cts.WebChromeClientTest#testBlockWindowsAsync;android.webkit.cts.WebViewTest#testGetVisibleTitleHeight;android.webkit.cts.WebBackForwardListTest#testClone;android.webkit.cts.WebSettingsTest#testAccessDefaultTextEncodingName;android.webkit.cts.URLUtilTest#testGuessUrl;android.webkit.cts.MimeTypeMapTest#testAndroidTestCaseSetupProperly;android.webkit.cts.WebChromeClientTest#testOnReceivedIcon;android.webkit.cts.CookieTest#testAndroidTestCaseSetupProperly;android.webkit.cts.CookieManagerTest#testRemoveCookies;android.webkit.cts.WebSettingsTest#testAccessPluginsPath;android.webkit.cts.WebSettingsTest#testAccessAllowFileAccess;android.webkit.cts.WebSettingsTest#testAccessSupportMultipleWindows;android.webkit.cts.WebViewTest#testAppCanInjectHeadersViaImmutableMap;android.webkit.cts.WebViewTest#testSecureSiteSetsCertificate;android.webkit.cts.WebViewTest#testSetWebViewClient;android.webkit.cts.WebViewTest#testSetScrollBarStyle;android.webkit.cts.CookieTest#testDomain;android.webkit.cts.WebViewTest#testZoom;android.webkit.cts.URLUtilTest#testIsDataUrl;android.webkit.cts.CookieManagerTest#testAcceptCookie;android.webkit.cts.WebChromeClientTest#testOnReceivedTitle;android.webkit.cts.URLUtilTest#testIsFileUrl;android.webkit.cts.WebSettingsTest#testAccessJavaScriptEnabled;android.webkit.cts.URLUtilTest#testIsNetworkUrl;android.webkit.cts.WebViewTest#testFindAddress;android.webkit.cts.WebViewTest#testSetNetworkAvailable;android.webkit.cts.WebViewTest#testClearSslPreferences;android.webkit.cts.URLUtilTest#testIsHttpsUrl;android.webkit.cts.MimeTypeMapTest#testGetFileExtensionFromUrl;android.webkit.cts.WebViewTest#testGetOriginalUrl;android.webkit.cts.WebChromeClientTest#testBlockWindowsSync;android.webkit.cts.WebViewTest#testLoadData;android.webkit.cts.WebViewTest#testInsecureSiteClearsCertificate;android.webkit.cts.WebBackForwardListTest#testGetCurrentItem;android.webkit.cts.URLUtilTest#testStripAnchor;android.webkit.cts.URLUtilTest#testGuessFileName;android.webkit.cts.URLUtilTest#testAndroidTestCaseSetupProperly;android.webkit.cts.WebViewTest#testEvaluateJavascript;android.webkit.cts.DateSorterTest#testConstructor;android.webkit.cts.WebViewTest#testPageScroll;android.webkit.cts.WebSettingsTest#testIframesWhenAccessFromFileURLsEnabled;android.webkit.cts.WebViewTest#testFlingScroll;android.webkit.cts.WebSettingsTest#testXHRWhenAccessFromFileURLsEnabled;android.webkit.cts.WebChromeClientTest#testOnJsPrompt;android.webkit.cts.WebSettingsTest#testAccessSupportZoom;android.webkit.cts.WebSettingsTest#testLoadsImagesAutomatically;android.webkit.cts.URLUtilTest#testIsValidUrl;android.webkit.cts.WebViewTest#testRequestFocusNodeHref;android.webkit.cts.WebViewTest#testLoadDataWithBaseUrl;android.webkit.cts.WebChromeClientTest#testOnJsAlert;android.webkit.cts.WebSettingsTest#testAccessSansSerifFontFamily;android.webkit.cts.CookieManagerTest#testCookieManager;android.webkit.cts.WebViewTest#testSetMapTrackballToArrowKeys;android.webkit.cts.WebViewTest#testCreatingWebViewCreatesCookieSyncManager;android.webkit.cts.DateSorterTest#testGetIndex;android.webkit.cts.GeolocationTest#testGeolocationPermissions;android.webkit.cts.WebChromeClientTest#testOnJsBeforeUnload;android.webkit.cts.CookieManagerTest#testClone;android.webkit.cts.CookieManagerTest#testGetInstance;android.webkit.cts.WebViewTest#testGetZoomControls;android.webkit.cts.CookieTest#testSubDomain;android.webkit.cts.WebSettingsTest#testUserAgentString_default;android.webkit.cts.MimeTypeMapTest#testGetMimeTypeFromExtension;android.webkit.cts.WebSettingsTest#testBlockNetworkImage;android.webkit.cts.WebViewTest#testPlatformNotifications;android.webkit.cts.URLUtilTest#testIsAboutUrl;android.webkit.cts.WebViewTest#testSetPictureListener;android.webkit.cts.MimeTypeMapTest#testHasMimeType;android.webkit.cts.WebViewTest#testOnReceivedSslErrorProceed;android.webkit.cts.DateSorterTest#testGetLabel;android.webkit.cts.GeolocationTest#testSimpleGeolocationRequestAcceptAlways;android.webkit.cts.URLUtilTest#testDecode;android.webkit.cts.HttpAuthHandlerTest#testProceed;android.webkit.cts.WebSettingsTest#testSetNeedInitialFocus;android.webkit.cts.WebSettingsTest#testIframesWhenAccessFromFileURLsDisabled;android.webkit.cts.WebSettingsTest#testAccessCursiveFontFamily;android.webkit.cts.WebViewTest#testFindAll;android.webkit.cts.WebViewTest#testStopLoading;android.webkit.cts.DateSorterTest#testAndroidTestCaseSetupProperly;android.webkit.cts.WebSettingsTest#testAccessDefaultFixedFontSize;android.webkit.cts.CookieManagerTest#testb3167208;android.webkit.cts.WebSettingsTest#testAccessMinimumFontSize;android.webkit.cts.WebSettingsTest#testAccessUseWideViewPort;android.webkit.cts.WebSettingsTest#testAccessSaveFormData;android.webkit.cts.WebViewTest#testRequestChildRectangleOnScreen;android.webkit.cts.URLUtilTest#testIsJavaScriptUrl;android.webkit.cts.WebViewTest#testFindNext;android.webkit.cts.MimeTypeMapTest#testHasExtension;android.webkit.cts.WebViewTest#testSetDownloadListener;android.webkit.cts.WebSettingsTest#testXHRWhenAccessFromFileURLsDisabled;android.webkit.cts.WebViewTest#testDestroy;android.webkit.cts.MimeTypeMapTest#testGetSingleton;android.webkit.cts.WebViewTest#testAndroidAssetQueryParam;android.webkit.cts.WebViewTest#testAccessPluginList;android.webkit.cts.CookieTest#testPath;android.webkit.cts.WebViewTest#testAccessHttpAuthUsernamePassword;android.webkit.cts.WebViewTest#testUseRemovedJavascriptInterface;android.webkit.cts.WebSettingsTest#testAccessTextSize;android.webkit.cts.URLUtilTest#testIsAssetUrl;android.webkit.cts.CookieTest#testInvalidDomain;android.webkit.cts.CookieSyncManagerTest#testCookieSyncManager;android.webkit.cts.URLUtilTest#testComposeSearchUrl;android.webkit.cts.WebChromeClientTest#testWindows;android.webkit.cts.WebViewTest#testRequestImageRef;android.webkit.cts.WebSettingsTest#testAccessDefaultFontSize;android.webkit.cts.WebViewClientTest#testShouldOverrideKeyEvent;android.webkit.cts.WebHistoryItemTest#testWebHistoryItem;android.webkit.cts.WebSettingsTest#testAccessBuiltInZoomControls;android.webkit.cts.WebSettingsTest#testAppCacheDisabled;android.webkit.cts.WebViewTest#testSetWebChromeClient;android.webkit.cts.WebViewTest#testGetHitTestResult;android.webkit.cts.WebSettingsTest#testAccessStandardFontFamily;android.webkit.cts.GeolocationTest#testSimpleGeolocationRequestReject;android.webkit.cts.WebSettingsTest#testBlockNetworkLoads;android.webkit.cts.DateSorterTest#testGetBoundary;android.webkit.cts.WebViewTest#testCapturePicture;android.webkit.cts.WebSettingsTest#testAccessPluginsEnabled;android.webkit.cts.WebViewTest#testSaveAndRestoreState;android.webkit.cts.WebViewTest#testLoadUrl;android.webkit.cts.HttpAuthHandlerTest#testCancel;android.webkit.cts.URLUtilTest#testIsCookielessProxyUrl;android.webkit.cts.WebViewTest#testGetFavicon;android.webkit.cts.MimeTypeMapTest#testGetExtensionFromMimeType" />
- <Entry uri="android.widget" exclude="android.widget.cts.ImageSwitcherTest#testSetImageDrawable;android.widget.cts.ExpandableListViewTest#testOnSaveInstanceState;android.widget.cts.RemoteViewsTest#testSetFloat;android.widget.cts.ToggleButtonTest#testConstructor;android.widget.cts.CursorTreeAdapterTest#testOnGroupCollapsed;android.widget.cts.ListViewTest#testDispatchDraw;android.widget.cts.HorizontalScrollViewTest#testRequestLayout;android.widget.cts.TextViewTest#testDrawableResolution;android.widget.cts.CursorTreeAdapterTest#testGetGroup;android.widget.cts.RemoteViewsTest#testSetBoolean;android.widget.cts.SimpleExpandableListAdapterTest#testGetChildrenCount;android.widget.cts.TimePickerTest#testSetEnabled;android.widget.cts.RemoteViewsTest#testSetChronometer;android.widget.cts.BaseExpandableListAdapterTest#testNotifyDataSetChanged;android.widget.cts.TextViewTest#testConstructor;android.widget.cts.FrameLayoutTest#testGenerateLayoutParams2;android.widget.cts.FrameLayoutTest#testGenerateLayoutParams1;android.widget.cts.DialerFilterTest#testClearText;android.widget.cts.ListViewTest#testFindViewWithTagTraversal;android.widget.cts.TextViewTest#testGetResolvedTextAlignmentWithInheritance;android.widget.cts.SimpleAdapterTest#testSetDropDownViewResource;android.widget.cts.GalleryTest#testShowContextMenu;android.widget.cts.ExpandableListViewTest#testSetChildIndicator;android.widget.cts.GalleryTest#testConstructor;android.widget.cts.CursorTreeAdapterTest#testGetGroupCount;android.widget.cts.TextViewTest#testDebug;android.widget.cts.ExpandableListViewTest#testSetIndicatorBounds;android.widget.cts.AutoCompleteTextViewTest#testOnKeyPreIme;android.widget.cts.TextViewTest#testOnTrackballEvent;android.widget.cts.ExpandableListViewTest#testAndroidTestCaseSetupProperly;android.widget.cts.PopupWindowTest#testAccessBackground;android.widget.cts.PopupWindowTest#testGetMaxAvailableHeight;android.widget.cts.TextViewTest#testGetTotalPaddingLeft;android.widget.cts.AutoCompleteTextViewTest#testAccessAdapter;android.widget.cts.AutoCompleteTextViewTest#testPerformCompletion;android.widget.cts.ZoomButtonTest#testDispatchUnhandledMove;android.widget.cts.AbsSpinnerTest#testOnMeasure;android.widget.cts.TextViewTest#testOnWindowFocusChanged;android.widget.cts.PopupWindowTest#testUpdateDimensionAndAlignAnchorViewWithOffsets;android.widget.cts.GridLayoutTest#testCheckLayoutParams;android.widget.cts.TabHostTest#testNewTabSpec;android.widget.cts.ViewAnimatorTest#testGetCurrentView;android.widget.cts.ListViewTest#testDispatchKeyEvent;android.widget.cts.TextViewTest#testSetMinEms;android.widget.cts.FrameLayoutTest#testGatherTransparentRegion;android.widget.cts.AbsListViewTest#testDraw;android.widget.cts.ZoomControlsTest#testHasFocus;android.widget.cts.RemoteViews_ActionExceptionTest#testConstructor;android.widget.cts.ViewFlipperTest#testActivityTestCaseSetUpProperly;android.widget.cts.RemoteViewsTest#testSetString;android.widget.cts.SimpleExpandableListAdapterTest#testConstructor;android.widget.cts.GalleryTest#testComputeHorizontalScrollExtent;android.widget.cts.DialerFilterTest#testGetFilterText;android.widget.cts.RadioGroupTest#testGenerateDefaultLayoutParams;android.widget.cts.DialerFilterTest#testSetFilterWatcher;android.widget.cts.CheckBoxTest#testConstructor;android.widget.cts.ProgressBarTest#testDrawableStateChanged;android.widget.cts.MultiAutoCompleteTextViewTest#testPerformFiltering;android.widget.cts.TextViewTest#testOnKeyMultiple;android.widget.cts.ProgressBarTest#testPostInvalidate;android.widget.cts.SlidingDrawerTest#testOpenAndClose;android.widget.cts.AutoCompleteTextViewTest#testConstructor;android.widget.cts.TextViewTest#testSetLineSpacing;android.widget.cts.ListViewTest#testFindViewTraversal;android.widget.cts.RadioGroupTest#testGetCheckedRadioButtonId;android.widget.cts.TabHostTest#testSetup2;android.widget.cts.TableLayout_LayoutParamsTest#testConstructor;android.widget.cts.HorizontalScrollViewTest#testRequestChildFocus;android.widget.cts.TabWidgetTest#testDispatchDraw;android.widget.cts.PopupWindowTest#testUpdate;android.widget.cts.BaseAdapterTest#testNotifyDataSetInvalidated;android.widget.cts.ProgressBarTest#testOnSaveAndRestoreInstanceState;android.widget.cts.TabHostTest#testSetup1;android.widget.cts.TextViewTest#testOnMeasure;android.widget.cts.CompoundButtonTest#testAccessInstanceState;android.widget.cts.TabWidgetTest#testOnFocusChange;android.widget.cts.DialerFilterTest#testOnFinishInflate;android.widget.cts.ImageViewTest#testSetSelected;android.widget.cts.TextViewTest#testDrawableResolution2;android.widget.cts.ExpandableListViewWithHeadersTest#testPreconditions;android.widget.cts.AbsListViewTest#testSetFilterText;android.widget.cts.ExpandableListViewTest#testGetAdapter;android.widget.cts.TextViewTest#testSingleLine;android.widget.cts.HorizontalScrollViewTest#testComputeScroll;android.widget.cts.CursorAdapterTest#testRunQueryOnBackgroundThread;android.widget.cts.ToastTest#testMakeText2;android.widget.cts.CursorAdapterTest#testGetView;android.widget.cts.ViewSwitcherTest#testSetFactory;android.widget.cts.ToastTest#testMakeText1;android.widget.cts.GridViewTest#testAccessStretchMode;android.widget.cts.AutoCompleteTextViewTest#testGetThreshold;android.widget.cts.RemoteViewsTest#testConstructor;android.widget.cts.AbsListViewTest#testCheckLayoutParams;android.widget.cts.ViewAnimatorTest#testSetAnimateFirstView;android.widget.cts.DigitalClockTest#testActivityTestCaseSetUpProperly;android.widget.cts.SlidingDrawerTest#testAnimateOpenAndClose;android.widget.cts.PopupWindowTest#testAccessFocusable;android.widget.cts.TimePickerTest#testSetOnTimeChangedListener;android.widget.cts.ScrollViewTest#testGetMaxScrollAmount;android.widget.cts.CursorAdapterTest#testOnContentChanged;android.widget.cts.TextViewTest#testGetTotalPaddingBottom;android.widget.cts.AnalogClockTest#testOnMeasure;android.widget.cts.RadioGroupTest#testCheck;android.widget.cts.CursorTreeAdapterTest#testNotifyDataSetChanged;android.widget.cts.TwoLineListItemTest#testActivityTestCaseSetUpProperly;android.widget.cts.AbsListViewTest#testGetContextMenuInfo;android.widget.cts.ViewAnimatorTest#testAccessOutAnimation;android.widget.cts.SlidingDrawerTest#testConstructor;android.widget.cts.TimePickerTest#testOnSaveInstanceStateAndOnRestoreInstanceState;android.widget.cts.AbsListViewTest#testAccessFastScrollEnabled;android.widget.cts.BaseAdapterTest#testGetItemViewType;android.widget.cts.AbsListViewTest#testSetOnScrollListener;android.widget.cts.ImageViewTest#testSetImageURI;android.widget.cts.RadioGroupTest#testOnFinishInflate;android.widget.cts.TableRowTest#testGenerateLayoutParams;android.widget.cts.DialerFilterTest#testGetLetters;android.widget.cts.HorizontalScrollViewTest#testComputeHorizontalScrollRange;android.widget.cts.TextViewTest#testSetPadding;android.widget.cts.VideoViewTest#testPlayVideo1;android.widget.cts.ArrayAdapterTest#testRemove;android.widget.cts.GridViewTest#testGetNumColumns;android.widget.cts.AbsSpinnerTest#testSetSelectionIntBoolean;android.widget.cts.LayoutDirectionTest#testDirectionForAllLayoutsWithCode;android.widget.cts.SimpleCursorAdapterTest#testAccessStringConversionColumn;android.widget.cts.ViewAnimatorTest#testGetBaseline;android.widget.cts.ChronometerTest#testConstructor;android.widget.cts.ResourceCursorTreeAdapterTest#testConstructor;android.widget.cts.AdapterViewTest#testGetPositionForView;android.widget.cts.GridViewTest#testSetVerticalSpacing;android.widget.cts.ButtonTest#testAndroidTestCaseSetupProperly;android.widget.cts.ToggleButtonTest#testToggleText;android.widget.cts.RatingBarTest#testSetMax;android.widget.cts.RemoteViewsTest#testSetViewVisibility;android.widget.cts.ScrollViewTest#testOnTouchEvent;android.widget.cts.BaseAdapterTest#testIsEnabled;android.widget.cts.ExpandableListViewTest#testSetOnChildClickListener;android.widget.cts.EditTextTest#testAndroidTestCaseSetupProperly;android.widget.cts.TextViewTest#testMarquee;android.widget.cts.ImageViewTest#testActivityTestCaseSetUpProperly;android.widget.cts.RadioGroupTest#testConstructors;android.widget.cts.DialerFilterTest#testAccessMode;android.widget.cts.DatePickerTest#testInit;android.widget.cts.TextViewTest#testGetTextColors;android.widget.cts.ProgressBarTest#testAccessProgress;android.widget.cts.TextViewTest#testGetPaint;android.widget.cts.SimpleExpandableListAdapterTest#testNewGroupView;android.widget.cts.AdapterView_AdapterContextMenuInfoTest#testConstructor;android.widget.cts.CompoundButtonTest#testConstructor;android.widget.cts.ImageViewTest#testSetImageLevel;android.widget.cts.SimpleCursorTreeAdapterTest#testBindGroupView;android.widget.cts.SimpleExpandableListAdapterTest#testGetGroup;android.widget.cts.TabWidgetTest#testFocusCurrentTab;android.widget.cts.RelativeLayoutTest#testOnLayout;android.widget.cts.ScrollViewTest#testComputeScroll;android.widget.cts.TextViewTest#testAccessHintTextColor;android.widget.cts.TableLayoutTest#testAccessShrinkAllColumns;android.widget.cts.RemoteViewsTest#testGetPackage;android.widget.cts.GridViewTest#testAttachLayoutAnimationParameters;android.widget.cts.LinearLayout_LayoutParamsTest#testAndroidTestCaseSetupProperly;android.widget.cts.CompoundButtonTest#testAndroidTestCaseSetupProperly;android.widget.cts.ImageViewTest#testSetImageDrawable;android.widget.cts.AdapterViewTest#testAccessVisiblePosition;android.widget.cts.ListViewTest#testSaveAndRestoreInstanceState;android.widget.cts.CompoundButtonTest#testToggle;android.widget.cts.TextViewTest#testMoveCursorToVisibleOffset;android.widget.cts.AutoCompleteTextViewTest#testAccessDropDownWidth;android.widget.cts.RadioGroupTest#testGenerateLayoutParams;android.widget.cts.AdapterViewTest#testCanAnimate;android.widget.cts.ScrollViewTest#testOnLayout;android.widget.cts.AutoCompleteTextViewTest#testEnoughToFilter;android.widget.cts.CheckedTextViewTest#testOnCreateDrawableState;android.widget.cts.RelativeLayout_LayoutParamsTest#testDebug;android.widget.cts.ToastTest#testAccessDuration;android.widget.cts.ToggleButtonTest#testSetChecked;android.widget.cts.HeaderViewListAdapterTest#testGetFootersCount;android.widget.cts.GridLayoutTest#testGenerateDefaultLayoutParams;android.widget.cts.AbsListViewTest#testAccessSmoothScrollbarEnabled;android.widget.cts.SlidingDrawerTest#testSetOnDrawerOpenListener;android.widget.cts.HeaderViewListAdapterTest#testGetHeadersCount;android.widget.cts.RemoteViewsTest#testSetLong;android.widget.cts.SlidingDrawerTest#testSetOnDrawerCloseListener;android.widget.cts.TextViewTest#testGetResolvedTextDirectionLtrWithInheritance;android.widget.cts.ScrollViewTest#testFullScroll;android.widget.cts.RelativeLayout_LayoutParamsTest#testAccessRule1;android.widget.cts.BaseExpandableListAdapterTest#testAreAllItemsEnabled;android.widget.cts.RelativeLayout_LayoutParamsTest#testAccessRule2;android.widget.cts.RemoteViewsActivityTest#testDerivedClass;android.widget.cts.ToastTest#testShowFailure;android.widget.cts.SimpleAdapterTest#testSetViewImage;android.widget.cts.TextViewTest#testAccessPrivateImeOptions;android.widget.cts.AdapterView_AdapterContextMenuInfoTest#testAndroidTestCaseSetupProperly;android.widget.cts.TwoLineListItemTest#testOnFinishInflate;android.widget.cts.ExpandableListViewTest#testGetExpandableListPosition;android.widget.cts.AbsListViewTest#testAccessListPadding;android.widget.cts.ExpandableListViewTest#testExpandGroup;android.widget.cts.TextViewTest#testGetUrls;android.widget.cts.LinearLayoutTest#testAccessBaselineAlignedChildIndex;android.widget.cts.CheckBoxTest#testAndroidTestCaseSetupProperly;android.widget.cts.ZoomControlsTest#testSetOnZoomInClickListener;android.widget.cts.AbsSpinnerTest#testGetCount;android.widget.cts.SimpleExpandableListAdapterTest#testNewChildView;android.widget.cts.ViewSwitcherTest#testConstructor;android.widget.cts.AutoCompleteTextViewTest#testReplaceText;android.widget.cts.ScrollViewTest#testAccessFillViewport;android.widget.cts.ToastTest#testShow;android.widget.cts.TextViewTest#testDrawableStateChanged;android.widget.cts.TimePickerTest#testGetBaseline;android.widget.cts.TextViewTest#testOnTouchEvent;android.widget.cts.ListViewTest#testOnFocusChanged;android.widget.cts.ImageViewTest#testDrawableStateChanged;android.widget.cts.FrameLayoutTest#testOnLayout;android.widget.cts.ListViewTest#testAccessItemsCanFocus;android.widget.cts.AutoCompleteTextViewTest#testOnCommitCompletion;android.widget.cts.ScrollViewTest#testAccessSmoothScrollingEnabled;android.widget.cts.TextViewTest#testSelection;android.widget.cts.CheckedTextViewTest#testOnDraw;android.widget.cts.ViewAnimatorTest#testConstructor;android.widget.cts.RadioGroupTest#testInternalPassThroughHierarchyChangeListener;android.widget.cts.SimpleCursorAdapterTest#testSetViewImage;android.widget.cts.AdapterViewTest#testGetSelected;android.widget.cts.ExpandableListViewWithHeadersTest#testSelectedPosition;android.widget.cts.ProgressBarTest#testAccessIndeterminateDrawable;android.widget.cts.TableLayoutTest#testSetOnHierarchyChangeListener;android.widget.cts.ExpandableListViewTest#testSetOnItemClickListener;android.widget.cts.ProgressBarTest#testSetVisibility;android.widget.cts.AutoCompleteTextViewTest#testConvertSelectionToString;android.widget.cts.ImageViewTest#testSetImageResource;android.widget.cts.ScrollViewTest#testGetVerticalFadingEdgeStrengths;android.widget.cts.FilterTest#testFilter2;android.widget.cts.CursorTreeAdapterTest#testAndroidTestCaseSetupProperly;android.widget.cts.FilterTest#testFilter1;android.widget.cts.ZoomControlsTest#testSetIsZoomOutEnabled;android.widget.cts.ScrollViewTest#testMeasureChildWithMargins;android.widget.cts.CompoundButtonTest#testSetOnCheckedChangeListener;android.widget.cts.TextViewTest#testGetEditableText;android.widget.cts.HorizontalScrollViewTest#testOnRequestFocusInDescendants;android.widget.cts.AbsSpinnerTest#testAccessAdapter;android.widget.cts.ChronometerTest#testAccessOnChronometerTickListener;android.widget.cts.HeaderViewListAdapterTest#testConstructor;android.widget.cts.FrameLayoutTest#testSetForegroundGravity;android.widget.cts.AbsSpinnerTest#testGetSelectedView;android.widget.cts.TextViewTest#testSetGetTextAlignment;android.widget.cts.TextViewTest#testGetLayout;android.widget.cts.ImageViewTest#testConstructor;android.widget.cts.ImageViewTest#testInvalidateDrawable;android.widget.cts.PopupWindowTest#testShowAsDropDownWithOffsets;android.widget.cts.PopupWindowTest#testIsAboveAnchor;android.widget.cts.AutoCompleteTextViewTest#testPerformFiltering;android.widget.cts.ViewFlipperTest#testConstructor;android.widget.cts.DatePickerTest#testUpdateDate;android.widget.cts.MultiAutoCompleteTextViewTest#testMultiAutoCompleteTextView;android.widget.cts.MultiAutoCompleteTextView_CommaTokenizerTest#testConstructor;android.widget.cts.RemoteViewsTest#testSetOnClickPendingIntent;android.widget.cts.HorizontalScrollViewTest#testScrollTo;android.widget.cts.HorizontalScrollViewTest#testOnTouchEvent;android.widget.cts.ListViewTest#testOnMeasure;android.widget.cts.TextViewTest#testSetHighlightColor;android.widget.cts.BaseExpandableListAdapterTest#testNotifyDataSetInvalidated;android.widget.cts.ExpandableListViewWithHeadersTest#testConvertionBetweenFlatAndPacked;android.widget.cts.HeaderViewListAdapterTest#testRemoveFooter;android.widget.cts.ListViewTest#testTransientStateStableIds;android.widget.cts.ScrollViewTest#testSmoothScrollBy;android.widget.cts.ViewSwitcherTest#testAndroidTestCaseSetupProperly;android.widget.cts.TextViewTest#testAccessAutoLinkMask;android.widget.cts.ScrollerTest#testScrollModeWithDefaultDuration;android.widget.cts.GalleryTest#testComputeHorizontalScrollRange;android.widget.cts.CheckedTextViewTest#testSetPadding;android.widget.cts.CursorTreeAdapterTest#testGetGroupId;android.widget.cts.RemoteViewsTest#testApply;android.widget.cts.DialerFilterTest#testIsQwertyKeyboard;android.widget.cts.GalleryTest#testShowContextMenuForChild;android.widget.cts.ScrollViewTest#testPageScroll;android.widget.cts.SimpleCursorTreeAdapterTest#testSetViewImage;android.widget.cts.TableLayoutTest#testOnLayout;android.widget.cts.ArrayAdapterTest#testGetPosition;android.widget.cts.TabWidgetTest#testOnSizeChanged;android.widget.cts.SimpleCursorAdapterTest#testNewDropDownView;android.widget.cts.AutoCompleteTextViewTest#testAccessListSelection;android.widget.cts.TextViewTest#testSetText1;android.widget.cts.TextViewTest#testSetText2;android.widget.cts.RemoteViewsActivityTest#testWebView;android.widget.cts.TextViewTest#testSetText3;android.widget.cts.ToastTest#testAccessGravity;android.widget.cts.HorizontalScrollViewTest#testAddViewWithIndex;android.widget.cts.ResourceCursorTreeAdapterTest#testNewChildView;android.widget.cts.HeaderViewListAdapterTest#testAndroidTestCaseSetupProperly;android.widget.cts.ExpandableListViewTest#testGetPackedPositionForGroup;android.widget.cts.ZoomControlsTest#testShowAndHide;android.widget.cts.CompoundButtonTest#testAccessChecked;android.widget.cts.SimpleAdapterTest#testGetView;android.widget.cts.DialerFilterTest#testGetDigits;android.widget.cts.ArrayAdapterTest#testDataChangeEvent;android.widget.cts.ImageSwitcherTest#testAndroidTestCaseSetupProperly;android.widget.cts.SimpleExpandableListAdapterTest#testGetChildView;android.widget.cts.ZoomControlsTest#testConstructor;android.widget.cts.CompoundButtonTest#testVerifyDrawable;android.widget.cts.TextViewTest#testSetEms;android.widget.cts.AbsSpinnerTest#testGenerateDefaultLayoutParams;android.widget.cts.TextViewTest#testAccessError;android.widget.cts.ZoomButtonTest#testOnTouchEvent;android.widget.cts.TextViewTest#testSetMaxLinesException;android.widget.cts.CompoundButtonTest#testSetButtonDrawableById;android.widget.cts.FrameLayoutTest#testGenerateDefaultLayoutParams;android.widget.cts.HorizontalScrollViewTest#testComputeScrollDeltaToGetChildRectOnScreen;android.widget.cts.ExpandableListViewTest#testSetSelectedChild;android.widget.cts.MediaControllerTest#testShow;android.widget.cts.CursorAdapterTest#testGetDropDownView;android.widget.cts.ListViewTest#testNoSelectableItems;android.widget.cts.TextViewTest#testGetBaseLine;android.widget.cts.AbsSpinnerTest#testConstructor;android.widget.cts.ListViewTest#testAccessDividerHeight;android.widget.cts.TabWidgetTest#testChildDrawableStateChanged;android.widget.cts.AbsListViewTest#testAccessSelectedItem;android.widget.cts.ScrollerTest#testTimePassed;android.widget.cts.ArrayAdapterTest#testGetItem;android.widget.cts.ImageViewTest#testVerifyDrawable;android.widget.cts.ProgressBarTest#testConstructor;android.widget.cts.ProgressBarTest#testIncrementSecondaryProgressBy;android.widget.cts.CursorTreeAdapterTest#testSetChildrenCursor;android.widget.cts.FrameLayoutTest#testCheckLayoutParams;android.widget.cts.AbsoluteLayoutTest#testGenerateDefaultLayoutParams;android.widget.cts.ZoomButtonTest#testOnKeyUp;android.widget.cts.BaseExpandableListAdapterTest#testGetCombinedId;android.widget.cts.ListViewTest#testSetSelection;android.widget.cts.SimpleCursorAdapterTest#testNewView;android.widget.cts.AutoCompleteTextViewTest#testPopupWindow;android.widget.cts.TextView_SaveStateTest#testWriteToParcel;android.widget.cts.TabHost_TabSpecTest#testSetContent2;android.widget.cts.SeekBarTest#testConstructor;android.widget.cts.TabHost_TabSpecTest#testSetContent1;android.widget.cts.TextViewTest#testSetExtractedText;android.widget.cts.TabHost_TabSpecTest#testSetContent3;android.widget.cts.SimpleExpandableListAdapterTest#testGetGroupCount;android.widget.cts.TextViewTest#testComputeVerticalScrollRange;android.widget.cts.GridLayoutTest#testAlignment;android.widget.cts.ExpandableListViewTest#testGetPackedPositionForChild;android.widget.cts.FrameLayoutTest#testConstructor;android.widget.cts.CursorAdapterTest#testAndroidTestCaseSetupProperly;android.widget.cts.RelativeLayoutTest#testSetHorizontalGravity;android.widget.cts.GalleryTest#testDispatchKeyEvent;android.widget.cts.ToastTest#testSetText1;android.widget.cts.HorizontalScrollViewTest#testFullScroll;android.widget.cts.RemoteViewsTest#testSetCharSequence;android.widget.cts.ToastTest#testSetText2;android.widget.cts.HeaderViewListAdapterTest#testRemoveHeader;android.widget.cts.TextSwitcherTest#testSetCurrentText;android.widget.cts.TwoLineListItemTest#testConstructor;android.widget.cts.MediaControllerTest#testMediaController;android.widget.cts.ListViewTest#testConstructor;android.widget.cts.AbsListViewTest#testAccessSelector;android.widget.cts.BaseExpandableListAdapterTest#testDataSetObserver;android.widget.cts.BaseAdapterTest#testHasStableIds;android.widget.cts.TextViewTest#testAccessImeActionLabel;android.widget.cts.CompoundButtonTest#testSetButtonDrawableByDrawable;android.widget.cts.AbsListViewTest#testLayoutChildren;android.widget.cts.ImageViewTest#testClearColorFilter;android.widget.cts.TextViewTest#testGetResolvedTextDirectionRtl;android.widget.cts.CheckedTextViewTest#testChecked;android.widget.cts.MultiAutoCompleteTextViewTest#testReplaceText;android.widget.cts.DigitalClockTest#testOnDetachedFromWindow;android.widget.cts.CursorTreeAdapterTest#testGetChildView;android.widget.cts.FrameLayout_LayoutParamsTest#testAndroidTestCaseSetupProperly;android.widget.cts.ImageViewTest#testSetMaxWidth;android.widget.cts.TabHostTest#testDispatchWindowFocusChanged;android.widget.cts.DigitalClockTest#testConstructor;android.widget.cts.DialerFilterTest#testOnKeyUpDown;android.widget.cts.TextViewTest#testSetHorizontallyScrolling;android.widget.cts.HeaderViewListAdapterTest#testGetViewTypeCount;android.widget.cts.AbsSeekBarTest#testAccessKeyProgressIncrement;android.widget.cts.AbsSeekBarTest#testSetThumb;android.widget.cts.ProgressBarTest#testOnDraw;android.widget.cts.TextViewTest#testSetText;android.widget.cts.PopupWindowTest#testAccessContentView;android.widget.cts.GridLayoutTest#testConstructor;android.widget.cts.PopupWindowTest#testAccessHeight;android.widget.cts.ToggleButtonTest#testAndroidTestCaseSetupProperly;android.widget.cts.ProgressBarTest#testVerifyDrawable;android.widget.cts.TableRowTest#testOnLayout;android.widget.cts.RadioGroupTest#testInternalCheckedStateTracker;android.widget.cts.HorizontalScrollViewTest#testOnSizeChanged;android.widget.cts.ResourceCursorAdapterTest#testNewView;android.widget.cts.MultiAutoCompleteTextView_CommaTokenizerTest#testFindTokenEnd;android.widget.cts.ZoomButtonTest#testOnLongClick;android.widget.cts.AnalogClockTest#testOnDetachedFromWindow;android.widget.cts.TextViewTest#testSetMaxLines;android.widget.cts.ExpandableListViewTest#testPerformItemClick;android.widget.cts.TextViewTest#testResetTextDirection;android.widget.cts.ScrollViewTest#testScrollTo;android.widget.cts.TableLayoutTest#testGenerateDefaultLayoutParams;android.widget.cts.ImageViewTest#testSetAdjustViewBounds;android.widget.cts.TableRowTest#testCheckLayoutParams;android.widget.cts.CheckedTextViewTest#testToggle;android.widget.cts.RemoteViewsTest#testSetProgressBar;android.widget.cts.VideoViewTest#testSetOnErrorListener;android.widget.cts.GalleryTest#testDispatchSetPressed;android.widget.cts.HorizontalScrollViewTest#testSmoothScrollTo;android.widget.cts.ZoomControlsTest#testSetZoomSpeed;android.widget.cts.ExpandableListViewTest#testSetAdapter;android.widget.cts.AutoCompleteTextViewTest#testOnFilterComplete;android.widget.cts.ImageViewTest#testGetDrawable;android.widget.cts.CursorTreeAdapterTest#testRunQueryOnBackgroundThread;android.widget.cts.SlidingDrawerTest#testGetHandle;android.widget.cts.BaseAdapterTest#testAndroidTestCaseSetupProperly;android.widget.cts.MediaControllerTest#testOnTrackballEvent;android.widget.cts.GalleryTest#testGenerateLayoutParams;android.widget.cts.PopupWindowTest#testConstructor;android.widget.cts.GalleryTest#testFoo;android.widget.cts.PopupWindowTest#testAccessAnimationStyle;android.widget.cts.ToggleButtonTest#testAccessTextOn;android.widget.cts.AbsoluteLayoutTest#testGenerateLayoutParams1;android.widget.cts.TextViewTest#testGetDefaultEditable;android.widget.cts.AbsoluteLayoutTest#testGenerateLayoutParams2;android.widget.cts.ArrayAdapterTest#testGetFilter;android.widget.cts.CheckedTextViewTest#testSetCheckMarkDrawableById;android.widget.cts.ScrollerTest#testAbortAnimation;android.widget.cts.LinearLayout_LayoutParamsTest#testConstructor;android.widget.cts.TextViewTest#testComputeVerticalScrollExtent;android.widget.cts.AbsSpinnerTest#testSetSelectionInt;android.widget.cts.TabHostTest#testGetTabContentView;android.widget.cts.TextViewTest#testGetDefaultMovementMethod;android.widget.cts.ScrollViewTest#testRequestChildRectangleOnScreen;android.widget.cts.TabHostTest#testGetCurrentView;android.widget.cts.TextViewTest#testAccessFilters;android.widget.cts.GalleryTest#testCheckLayoutParams;android.widget.cts.RadioGroup_LayoutParamsTest#testConstructor;android.widget.cts.BaseExpandableListAdapterTest#testOnGroupExpanded;android.widget.cts.MultiAutoCompleteTextView_CommaTokenizerTest#testTerminateToken;android.widget.cts.ScrollViewTest#testConstructor;android.widget.cts.ListViewTest#testLayoutChildren;android.widget.cts.RemoteViewsTest#testSetImageViewUri;android.widget.cts.ViewAnimatorTest#testAccessDisplayedChild;android.widget.cts.ExpandableListViewTest#testCollapseGroup;android.widget.cts.AnalogClockTest#testConstructor;android.widget.cts.CursorAdapterTest#testConvertToString;android.widget.cts.BaseAdapterTest#testIsEmpty;android.widget.cts.ResourceCursorTreeAdapterTest#testNewGroupView;android.widget.cts.ScrollViewTest#testFling;android.widget.cts.SlidingDrawerTest#testOnMeasure;android.widget.cts.TextViewTest#testSetMaxEms;android.widget.cts.LinearLayoutTest#testGenerateLayoutParams;android.widget.cts.PopupWindowTest#testAccessInputMethodMode;android.widget.cts.ListViewTest#testPerformItemClick;android.widget.cts.TextViewTest#testOnTextChanged;android.widget.cts.GridViewTest#testSetSelection;android.widget.cts.CursorAdapterTest#testHasStableIds;android.widget.cts.ProgressBarTest#testSetIndeterminate;android.widget.cts.TableRowTest#testGetVirtualChildCount;android.widget.cts.AutoCompleteTextViewTest#testOnTextChanged;android.widget.cts.TextViewTest#testSetLinesException;android.widget.cts.TextViewTest#testLength;android.widget.cts.RelativeLayoutTest#testSetGravity;android.widget.cts.RelativeLayoutTest#testConstructor;android.widget.cts.TextViewTest#testGetLineHeight;android.widget.cts.GalleryTest#testSetAnimationDuration;android.widget.cts.PopupWindowTest#testAccessTouchable;android.widget.cts.RelativeLayoutTest#testSetVerticalGravity;android.widget.cts.CursorTreeAdapterTest#testConstructor;android.widget.cts.AbsSpinnerTest#testRequestLayout;android.widget.cts.TextViewTest#testOnKeyShortcut;android.widget.cts.TableRowTest#testGetVirtualChildAt;android.widget.cts.SpinnerTest#testConstructor;android.widget.cts.SimpleAdapterTest#testGetDropDownView;android.widget.cts.ScrollViewTest#testAddViewWithLayoutParams;android.widget.cts.HeaderViewListAdapterTest#testGetItemViewType;android.widget.cts.RadioGroupTest#testSetOnCheckedChangeListener;android.widget.cts.ToggleButtonTest#testOnFinishInflate;android.widget.cts.DialerFilterTest#testAppend;android.widget.cts.HorizontalScrollViewTest#testRequestChildRectangleOnScreen;android.widget.cts.RadioButtonTest#testConstructor;android.widget.cts.PopupWindowTest#testDismiss;android.widget.cts.TableLayoutTest#testAddView2;android.widget.cts.TableLayoutTest#testAddView3;android.widget.cts.TabHostTest#testOnTouchModeChanged;android.widget.cts.TableLayoutTest#testAddView4;android.widget.cts.HeaderViewListAdapterTest#testGetWrappedAdapter;android.widget.cts.TableLayoutTest#testAddView1;android.widget.cts.ImageSwitcherTest#testSetImageResource;android.widget.cts.ToggleButtonTest#testDrawableStateChanged;android.widget.cts.EditTextTest#testSetSelectionIndex;android.widget.cts.EditTextTest#testExtendSelection;android.widget.cts.AbsSeekBarTest#testSetMax;android.widget.cts.CursorTreeAdapterTest#testChangeCursor;android.widget.cts.AdapterViewTest#testItemOrItemIdAtPosition;android.widget.cts.HorizontalScrollViewTest#testDispatchKeyEvent;android.widget.cts.TableRowTest#testGenerateDefaultLayoutParams;android.widget.cts.AbsListViewTest#testSetRecyclerListener;android.widget.cts.GalleryTest#testGetContextMenuInfo;android.widget.cts.AbsListViewTest#testAccessStackFromBottom;android.widget.cts.TextViewTest#testAccessText;android.widget.cts.SpinnerTest#testGetBaseline;android.widget.cts.ScrollViewTest#testRequestChildFocus;android.widget.cts.LinearLayoutTest#testGenerateDefaultLayoutParams;android.widget.cts.ButtonTest#testConstructor;android.widget.cts.ResourceCursorAdapterTest#testSetViewResource;android.widget.cts.ExpandableListViewBasicTest#testContextMenus;android.widget.cts.FrameLayoutTest#testVerifyDrawable;android.widget.cts.ExpandableListViewTest#testGetPackedPositionType;android.widget.cts.LinearLayoutTest#testLayoutHorizontal;android.widget.cts.ScrollViewTest#testComputeVerticalScrollRange;android.widget.cts.GridViewTest#testOnFocusChanged;android.widget.cts.ZoomControlsTest#testOnTouchEvent;android.widget.cts.GridViewTest#testActivityTestCaseSetUpProperly;android.widget.cts.ListViewTest#testAccessItemChecked;android.widget.cts.AbsoluteLayoutTest#testConstructor;android.widget.cts.TextViewTest#testComputeHorizontalScrollRange;android.widget.cts.HorizontalScrollViewTest#testAddViewWithLayoutParams;android.widget.cts.RemoteViewsTest#testGetLayoutId;android.widget.cts.CursorTreeAdapterTest#testNotifyDataSetChangedBoolean;android.widget.cts.TableRow_LayoutParamsTest#testSetBaseAttributes;android.widget.cts.HorizontalScrollViewTest#testMeasureChildWithMargins;android.widget.cts.TextViewTest#testSetIncludeFontPadding;android.widget.cts.HorizontalScrollViewTest#testAddView;android.widget.cts.TimePickerTest#testAccessCurrentMinute;android.widget.cts.TextViewTest#testGetExtendedPaddingBottom;android.widget.cts.BaseExpandableListAdapterTest#testIsEmpty;android.widget.cts.SimpleAdapterTest#testAccessViewBinder;android.widget.cts.SpinnerTest#testOnLayout;android.widget.cts.AutoCompleteTextViewTest#testAccessValidater;android.widget.cts.ScrollViewTest#testAddViewWithIndex;android.widget.cts.FrameLayoutTest#testDrawableStateChanged;android.widget.cts.PopupWindowTest#testSetTouchInterceptor;android.widget.cts.SimpleAdapterTest#testGetItem;android.widget.cts.ImageViewTest#testSetColorFilter1;android.widget.cts.ImageViewTest#testSetColorFilter2;android.widget.cts.SlidingDrawerTest#testDispatchDraw;android.widget.cts.TextViewTest#testSetOnEditorActionListener;android.widget.cts.DatePickerTest#testSetEnabled;android.widget.cts.RemoteViewsTest#testReapply;android.widget.cts.TextViewTest#testCompound;android.widget.cts.AdapterViewTest#testAccessEmptyView;android.widget.cts.Gallery_LayoutParamsTest#testConstructor;android.widget.cts.TextViewTest#testGetResolvedTextDirectionRtlWithInheritance;android.widget.cts.PopupWindowTest#testShowAtLocation;android.widget.cts.TextViewTest#testPerformLongClick;android.widget.cts.ExpandableListViewTest#testSetChildDivider;android.widget.cts.PopupWindowTest#testAccessClippingEnabled;android.widget.cts.RemoteViewsTest#testSetTextViewText;android.widget.cts.ScrollViewTest#testMeasureChild;android.widget.cts.TableLayoutTest#testAccessColumnShrinkable;android.widget.cts.TableRow_LayoutParamsTest#testConstructor;android.widget.cts.GalleryTest#testComputeHorizontalScrollOffset;android.widget.cts.ProgressBarTest#testOnMeasure;android.widget.cts.ProgressBarTest#testAccessProgressDrawable;android.widget.cts.SimpleAdapterTest#testGetFilter;android.widget.cts.RadioGroupTest#testSetOnHierarchyChangeListener;android.widget.cts.AbsListViewTest#testHandleDataChanged;android.widget.cts.AbsListViewTest#testShowContextMenuForChild;android.widget.cts.ExpandableListViewTest#testConstructor;android.widget.cts.HeaderViewListAdapterTest#testIsEmpty;android.widget.cts.AlphabetIndexerTest#testAlphabetIndexer;android.widget.cts.ChronometerTest#testAccessBase;android.widget.cts.TextViewTest#testAccessRawContentType;android.widget.cts.ScrollViewTest#testExecuteKeyEvent;android.widget.cts.SpinnerTest#testAccessPrompt;android.widget.cts.AnalogClockTest#testOnDraw;android.widget.cts.ChronometerTest#testStartAndStop;android.widget.cts.TabWidgetTest#testSetCurrentTab;android.widget.cts.CursorTreeAdapterTest#testGetFilter;android.widget.cts.ImageSwitcherTest#testSetImageURI;android.widget.cts.TabHostTest#testSetOnTabChangedListener;android.widget.cts.ScrollViewTest#testSmoothScrollTo;android.widget.cts.SimpleExpandableListAdapterTest#testGetGroupId;android.widget.cts.AbsListViewTest#testAccessCacheColorHint;android.widget.cts.TabHostTest#testSetCurrentTabByTag;android.widget.cts.HeaderViewListAdapterTest#testIsEnabled;android.widget.cts.ImageViewTest#testSetImageState;android.widget.cts.ExpandableListViewTest#testSetSelectedGroup;android.widget.cts.DialerFilterTest#testRemoveFilterWatcher;android.widget.cts.ToggleButtonTest#testAccessTextOff;android.widget.cts.TextViewTest#testSetSelectAllOnFocus;android.widget.cts.TextViewTest#testAccessKeyListener;android.widget.cts.ArrayAdapterTest#testInsert;android.widget.cts.MediaControllerTest#testSetPrevNextListeners;android.widget.cts.PopupWindowTest#testUpdatePositionAndDimension;android.widget.cts.TextViewTest#testOnDraw;android.widget.cts.TextViewTest#testSetFrame;android.widget.cts.ScrollerTest#testAccessFinalX;android.widget.cts.ScrollerTest#testAccessFinalY;android.widget.cts.AdapterViewTest#testOnLayout;android.widget.cts.ScrollViewTest#testOnRequestFocusInDescendants;android.widget.cts.TextViewTest#testCancelLongPress;android.widget.cts.GridViewTest#testAccessAdapter;android.widget.cts.ZoomButtonTest#testSetZoomSpeed;android.widget.cts.ExpandableListViewTest#testGetPackedPositionGroup;android.widget.cts.ExpandableListViewTest#testSetGroupIndicator;android.widget.cts.TextViewTest#testGetResolvedTextDirectionLtr;android.widget.cts.BaseAdapterTest#testGetDropDownView;android.widget.cts.ViewAnimatorTest#testShowPrevious;android.widget.cts.TextViewTest#testOnCreateContextMenu;android.widget.cts.TextViewTest#testAppend;android.widget.cts.DialerFilterTest#testOnFocusChanged;android.widget.cts.SlidingDrawerTest#testOnLayout;android.widget.cts.TextViewTest#testGetFocusedRect;android.widget.cts.TextSwitcherTest#testAddView;android.widget.cts.ExpandableListViewTest#testSetChildIndicatorBounds;android.widget.cts.RemoteViewsTest#testSetImageViewBitmap;android.widget.cts.CursorTreeAdapterTest#testHasStableIds;android.widget.cts.ToastTest#testConstructor;android.widget.cts.CursorTreeAdapterTest#testConvertToString;android.widget.cts.AbsListViewTest#testGetTopBottomFadingEdgeStrength;android.widget.cts.EditTextTest#testGetDefaultMovementMethod;android.widget.cts.AbsListViewTest#testAddTouchables;android.widget.cts.SeekBarTest#testSetOnSeekBarChangeListener;android.widget.cts.TextViewTest#testAccessLinkTextColor;android.widget.cts.TextViewTest#testAccessEllipsize;android.widget.cts.RatingBarTest#testAccessNumStars;android.widget.cts.ImageViewTest#testGetBaseline;android.widget.cts.AnalogClockTest#testOnAttachedToWindow;android.widget.cts.LayoutDirectionTest#testDirectionInheritanceForAllLayoutsWithCode;android.widget.cts.AutoCompleteTextViewTest#testAccessItemSelectedListener;android.widget.cts.TextSwitcherTest#testConstructor;android.widget.cts.TextViewTest#testGetResolvedTextAlignment;android.widget.cts.ExpandableListView_ExpandableListContextMenuInfoTest#testConstructor;android.widget.cts.HeaderViewListAdapterTest#testGetFilter;android.widget.cts.AbsSeekBarTest#testConstructor;android.widget.cts.ZoomControlsTest#testSetOnZoomOutClickListener;android.widget.cts.ArrayAdapterTest#testSort;android.widget.cts.HorizontalScrollViewTest#testFling;android.widget.cts.GridViewTest#testConstructor;android.widget.cts.RemoteViewsTest#testNotFeasibleSetters;android.widget.cts.RemoteViewsTest#testWriteToParcel;android.widget.cts.ScrollViewTest#testAddView;android.widget.cts.FilterTest#testConstructor;android.widget.cts.SimpleExpandableListAdapterTest#testGetChildId;android.widget.cts.AutoCompleteTextViewTest#testOnDetachedFromWindow;android.widget.cts.ScrollViewTest#testRequestLayout;android.widget.cts.ImageButtonTest#testConstructor;android.widget.cts.EditTextTest#testSelectAll;android.widget.cts.PopupWindowTest#testSetOnDismissListener;android.widget.cts.TimePickerTest#testAccessCurrentHour;android.widget.cts.ArrayAdapterTest#testCreateFromResource;android.widget.cts.TextViewTest#testSetShadowLayer;android.widget.cts.CompoundButtonTest#testOnCreateDrawableState;android.widget.cts.SimpleCursorAdapterTest#testChangeCursorAndColumns;android.widget.cts.ImageViewTest#testSetFrame;android.widget.cts.ArrayAdapterTest#testSetDropDownViewResouce;android.widget.cts.ResourceCursorAdapterTest#testNewDropDownView;android.widget.cts.ToastTest#testCancel;android.widget.cts.RatingBarTest#testAccessStepSize;android.widget.cts.CheckedTextViewTest#testSetCheckMarkDrawableByDrawable;android.widget.cts.TextViewTest#testInstanceState;android.widget.cts.AbsListViewTest#testGetFocusedRect;android.widget.cts.ViewAnimatorTest#testAddView;android.widget.cts.AdapterViewTest#testUnsupportedMethods;android.widget.cts.TextViewTest#testOnPrivateIMECommand;android.widget.cts.CursorAdapterTest#testAccessCursor;android.widget.cts.TextViewTest#testBringPointIntoView;android.widget.cts.SpinnerTest#testOnClick;android.widget.cts.TextViewTest#testSetEditableFactory;android.widget.cts.ViewSwitcherTest#testGetNextView;android.widget.cts.AbsSeekBarTest#testAccessThumbOffset;android.widget.cts.AbsoluteLayout_LayoutParamsTest#testDebug;android.widget.cts.DatePickerTest#testAccessDate;android.widget.cts.CursorAdapterTest#testConstructor;android.widget.cts.HorizontalScrollViewTest#testPageScroll;android.widget.cts.AutoCompleteTextViewTest#testPerformValidation;android.widget.cts.TextViewTest#testAccessLinksClickable;android.widget.cts.SlidingDrawerTest#testGetContent;android.widget.cts.ViewAnimatorTest#testShowNext;android.widget.cts.TextViewTest#testResetTextAlignment;android.widget.cts.ScrollerTest#testFlingMode;android.widget.cts.SlidingDrawerTest#testOnInterceptTouchEvent;android.widget.cts.DatePickerTest#testConstructor;android.widget.cts.TableLayoutTest#testAccessColumnCollapsed;android.widget.cts.AbsSeekBarTest#testVerifyDrawable;android.widget.cts.ScrollViewTest#testOnSizeChanged;android.widget.cts.TimePickerTest#testConstructors;android.widget.cts.TextViewTest#testAccessTransformationMethod;android.widget.cts.SimpleCursorTreeAdapterTest#testBindChildView;android.widget.cts.ScrollerTest#testExtendDuration;android.widget.cts.RatingBarTest#testAccessRating;android.widget.cts.RelativeLayoutTest#testCheckLayoutParams;android.widget.cts.GalleryTest#testGenerateDefaultLayoutParams;android.widget.cts.AbsoluteLayoutTest#testCheckLayoutParams;android.widget.cts.SlidingDrawerTest#testOnFinishInflate;android.widget.cts.EditTextTest#testSetSelectionStartstop;android.widget.cts.ToggleButtonTest#testSetBackgroundDrawable;android.widget.cts.HeaderViewListAdapterTest#testRegisterDataSetObserver;android.widget.cts.TextViewTest#testAccessFreezesText;android.widget.cts.ArrayAdapterTest#testAndroidTestCaseSetupProperly;android.widget.cts.ExpandableListViewTest#testGetSelectedPosition;android.widget.cts.TabHostTest#testGetCurrentTabTag;android.widget.cts.GridViewTest#testOnMeasure;android.widget.cts.HeaderViewListAdapterTest#testGetItemId;android.widget.cts.RadioButtonTest#testToggle;android.widget.cts.TextViewTest#testOnFocusChanged;android.widget.cts.AbsoluteLayout_LayoutParamsTest#testAndroidTestCaseSetupProperly;android.widget.cts.ViewAnimatorTest#testAccessInAnimation;android.widget.cts.AdapterViewTest#testDispatchSaveInstanceState;android.widget.cts.HeaderViewListAdapterTest#testHasStableIds;android.widget.cts.RelativeLayoutTest#testOnMeasure;android.widget.cts.HorizontalScrollViewTest#testSmoothScrollBy;android.widget.cts.ListViewTest#testTransientStateUnstableIds;android.widget.cts.TableRowTest#testConstructor;android.widget.cts.TabHost_TabSpecTest#testSetIndicator2;android.widget.cts.ArrayAdapterTest#testAccessView;android.widget.cts.TabHost_TabSpecTest#testSetIndicator1;android.widget.cts.HorizontalScrollViewTest#testAccessSmoothScrollingEnabled;android.widget.cts.TextViewTest#testSetCursorVisible;android.widget.cts.FrameLayout_LayoutParamsTest#testConstructor;android.widget.cts.AutoCompleteTextViewTest#testOnAttachedToWindow;android.widget.cts.CursorAdapterTest#testInit;android.widget.cts.SimpleAdapterTest#testGetItemId;android.widget.cts.TableLayout_LayoutParamsTest#testSetBaseAttributes;android.widget.cts.ExpandableListViewBasicTest#testExpandedGroupMovement;android.widget.cts.TextViewTest#testAccessPaintFlags;android.widget.cts.CursorAdapterTest#testGetItemId;android.widget.cts.GalleryTest#testSetSpacing;android.widget.cts.TextViewTest#testSetLines;android.widget.cts.ScrollerTest#testConstructor;android.widget.cts.CompoundButtonTest#testOnDraw;android.widget.cts.ListViewTest#testGetMaxScrollAmount;android.widget.cts.TwoLineListItemTest#testGetTexts;android.widget.cts.AbsListViewTest#testBeforeAndAfterTextChanged;android.widget.cts.AdapterViewTest#testConstructor;android.widget.cts.SimpleAdapterTest#testSetViewText;android.widget.cts.ExpandableListViewTest#testGetSelectedId;android.widget.cts.TableLayoutTest#testOnMeasure;android.widget.cts.DialerFilterTest#testSetDigitsWatcher;android.widget.cts.AbsListViewTest#testPointToPosition;android.widget.cts.ExpandableListViewTest#testGetPackedPositionChild;android.widget.cts.ExpandableListViewBasicTest#testSelectedPosition;android.widget.cts.RemoteViewsTest#testSetBitmap;android.widget.cts.TextViewTest#testFoo;android.widget.cts.EditTextTest#testAccessText;android.widget.cts.AbsListViewTest#testComputeVerticalScrollValues;android.widget.cts.VideoViewTest#testConstructor;android.widget.cts.EditTextTest#testGetDefaultEditable;android.widget.cts.EditTextTest#testConstructor;android.widget.cts.ExpandableListViewWithHeadersTest#testExpandOnFirstGroup;android.widget.cts.RelativeLayout_LayoutParamsTest#testStartEnd;android.widget.cts.ScrollViewTest#testAddViewWithIndexAndLayoutParams;android.widget.cts.ViewFlipperTest#testSetFlipInterval;android.widget.cts.ZoomButtonTest#testConstructor;android.widget.cts.TableRowTest#testOnMeasure;android.widget.cts.TableLayoutTest#testAccessStretchAllColumns;android.widget.cts.GridViewTest#testSetHorizontalSpacing;android.widget.cts.ExpandableListViewWithHeadersTest#testContextMenus;android.widget.cts.ListViewTest#testRequestChildRectangleOnScreen;android.widget.cts.VideoViewTest#testSetMediaController;android.widget.cts.AdapterViewTest#testAccessOnItemClickAndLongClickListener;android.widget.cts.RemoteViewsTest#testSetImageViewResource;android.widget.cts.TextViewTest#testScroll;android.widget.cts.VideoViewTest#testResolveAdjustedSize;android.widget.cts.ScrollViewTest#testOnInterceptTouchEvent;android.widget.cts.ViewAnimatorTest#testRemoveViews;android.widget.cts.AlphabetIndexerTest#testAndroidTestCaseSetupProperly;android.widget.cts.ImageViewTest#testSetMaxHeight;android.widget.cts.ImageViewTest#testOnMeasure;android.widget.cts.RadioGroup_LayoutParamsTest#testSetBaseAttributes;android.widget.cts.AbsoluteLayoutTest#testOnMeasure;android.widget.cts.CompoundButtonTest#testPerformClick;android.widget.cts.ExpandableListViewTest#testAccessExpandableListAdapter;android.widget.cts.TextView_SaveStateTest#testToString;android.widget.cts.CursorTreeAdapterTest#testGetGroupView;android.widget.cts.TextViewTest#testPressKey;android.widget.cts.ProgressBarTest#testAccessMax;android.widget.cts.TextViewTest#testBeginEndBatchEdit;android.widget.cts.HeaderViewListAdapterTest#testGetItem;android.widget.cts.LinearLayoutTest#testActivityTestCaseSetUpProperly;android.widget.cts.TextViewTest#testSetGetTextDirection;android.widget.cts.HeaderViewListAdapterTest#testGetView;android.widget.cts.ScrollerTest#testScrollMode;android.widget.cts.ProgressBarTest#testAccessInterpolator;android.widget.cts.TextViewTest#testTextAttr;android.widget.cts.AbsListViewTest#testAccessScrollingCacheEnabled;android.widget.cts.MediaControllerTest#testSetEnabled;android.widget.cts.SimpleCursorAdapterTest#testConvertToString;android.widget.cts.ExpandableListViewTest#testDispatchDraw;android.widget.cts.DigitalClockTest#testOnAttachedToWindow;android.widget.cts.BaseAdapterTest#testGetViewTypeCount;android.widget.cts.CursorAdapterTest#testGetCount;android.widget.cts.ToastTest#testAccessView;android.widget.cts.FrameLayoutTest#testOnMeasure;android.widget.cts.HorizontalScrollViewTest#testGetMaxScrollAmount;android.widget.cts.AbsListViewTest#testSetScrollIndicators;android.widget.cts.TabHostTest#testOnAttachedToAndDetachedFromWindow;android.widget.cts.CursorAdapterTest#testGetFilter;android.widget.cts.CursorTreeAdapterTest#testGetChild;android.widget.cts.SlidingDrawerTest#testSetOnDrawerScrollListener;android.widget.cts.ProgressBarTest#testOnSizeChange;android.widget.cts.TextViewTest#testGetTotalPaddingRight;android.widget.cts.GridViewTest#testPressKey;android.widget.cts.CheckedTextViewTest#testDrawableStateChanged;android.widget.cts.ScrollerTest#testGetDuration;android.widget.cts.TableLayoutTest#testRequestLayout;android.widget.cts.ImageViewTest#testAccessImageMatrix;android.widget.cts.PopupWindowTest#testAccessWidth;android.widget.cts.BaseAdapterTest#testDataSetObserver;android.widget.cts.SpinnerTest#testPerformClick;android.widget.cts.MediaControllerTest#testConstructor;android.widget.cts.SimpleCursorTreeAdapterTest#testConstructor;android.widget.cts.TextViewTest#testGetTextColor;android.widget.cts.DialerFilterTest#testOnModechange;android.widget.cts.AdapterViewTest#testDispatchRestoreInstanceState;android.widget.cts.ImageViewTest#testOnCreateDrawableState;android.widget.cts.CursorTreeAdapterTest#testNotifyDataSetInvalidated;android.widget.cts.SimpleExpandableListAdapterTest#testGetGroupView;android.widget.cts.ListViewTest#testRequestLayout;android.widget.cts.Gallery_LayoutParamsTest#testAndroidTestCaseSetupProperly;android.widget.cts.SimpleExpandableListAdapterTest#testGetChild;android.widget.cts.TableRowTest#testSetOnHierarchyChangeListener;android.widget.cts.TextViewTest#testGetExtendedPaddingTop;android.widget.cts.ResourceCursorAdapterTest#testSetDropDownViewResource;android.widget.cts.LinearLayoutTest#testAccessBaselineAligned;android.widget.cts.CursorTreeAdapterTest#testGetChildId;android.widget.cts.GridViewTest#testSetColumnWidth;android.widget.cts.AbsListViewTest#testAccessTranscriptMode;android.widget.cts.VideoViewTest#testGetBufferPercentage;android.widget.cts.LinearLayoutTest#testConstructor;android.widget.cts.TextViewTest#testAccessContentType;android.widget.cts.SimpleCursorAdapterTest#testBindView;android.widget.cts.SlidingDrawerTest#testOnTouchEvent;android.widget.cts.ListViewTest#testOnKeyUpDown;android.widget.cts.SimpleCursorAdapterTest#testAccessCursorToStringConverter;android.widget.cts.TabWidgetTest#testAddView;android.widget.cts.TextViewTest#testIsInputMethodTarget;android.widget.cts.AbsoluteLayout_LayoutParamsTest#testConstructor;android.widget.cts.RelativeLayoutTest#testGetBaseline;android.widget.cts.TextViewTest#testGetLineCount;android.widget.cts.GridLayoutTest#testActivityTestCaseSetUpProperly;android.widget.cts.ProgressBarTest#testInvalidateDrawable;android.widget.cts.AbsSpinnerTest#testOnSaveAndRestoreInstanceState;android.widget.cts.MultiAutoCompleteTextViewTest#testConstructor;android.widget.cts.ExpandableListViewTest#testGetFlatListPosition;android.widget.cts.ArrayAdapterTest#testAddAllParams;android.widget.cts.CursorTreeAdapterTest#testSetGroupCursor;android.widget.cts.TextViewTest#testDidTouchFocusSelect;android.widget.cts.SimpleCursorAdapterTest#testConstructor;android.widget.cts.TextViewTest#testAccessImeOptions;android.widget.cts.TabHostTest#testClearAllTabs;android.widget.cts.TextViewTest#testGetFadingEdgeStrength;android.widget.cts.TextViewTest#testSetMinLines;android.widget.cts.DialerFilterTest#testConstructor;android.widget.cts.AbsListViewTest#testConstructor;android.widget.cts.HorizontalScrollViewTest#testAddViewWithIndexAndLayoutParams;android.widget.cts.TextViewTest#testTextDirectionDefault;android.widget.cts.TextViewTest#testGetLineBounds;android.widget.cts.HorizontalScrollViewTest#testConstructor;android.widget.cts.AutoCompleteTextViewTest#testSetFrame;android.widget.cts.RelativeLayoutTest#testGenerateLayoutParams2;android.widget.cts.RelativeLayoutTest#testGenerateLayoutParams1;android.widget.cts.ArrayAdapterTest#testAdd;android.widget.cts.PopupWindowTest#testUpdateDimensionAndAlignAnchorView;android.widget.cts.ToastTest#testAccessMargin;android.widget.cts.RemoteViewsActivityTest#testGood;android.widget.cts.TextViewTest#testAccessTextSize;android.widget.cts.TableLayoutTest#testColumnStretchableEffect;android.widget.cts.CompoundButtonTest#testDrawableStateChanged;android.widget.cts.CursorAdapterTest#testAccessFilterQueryProvider;android.widget.cts.HorizontalScrollViewTest#testArrowScroll;android.widget.cts.ScrollViewTest#testOnMeasure;android.widget.cts.TextViewTest#testTextChangedListener;android.widget.cts.AutoCompleteTextViewTest#testSetCompletionHint;android.widget.cts.TextViewTest#testAccessTextColor;android.widget.cts.FrameLayoutTest#testAccessMeasureAllChildren;android.widget.cts.LinearLayoutTest#testAccessWeightSum;android.widget.cts.HorizontalScrollViewTest#testOnMeasure;android.widget.cts.ResourceCursorAdapterTest#testConstructor;android.widget.cts.FrameLayoutTest#testOnSizeChanged;android.widget.cts.LinearLayoutTest#testCheckLayoutParams;android.widget.cts.PopupWindowTest#testSetWindowLayoutMode;android.widget.cts.ExpandableListView_ExpandableListContextMenuInfoTest#testAndroidTestCaseSetupProperly;android.widget.cts.ListViewTest#testAccessHeaderView;android.widget.cts.RatingBarTest#testAccessOnRatingBarChangeListener;android.widget.cts.GridViewTest#testSetGravity;android.widget.cts.TextViewTest#testAccessHint;android.widget.cts.HorizontalScrollViewTest#testOnLayout;android.widget.cts.ListViewTest#testAccessAdapter;android.widget.cts.ArrayAdapterTest#testGetItemId;android.widget.cts.ImageButtonTest#testAndroidTestCaseSetupProperly;android.widget.cts.TextViewTest#testOnDetachedFromWindow;android.widget.cts.ProgressBarTest#testAccessSecondaryProgress;android.widget.cts.SimpleExpandableListAdapterTest#testIsChildSelectable;android.widget.cts.TextViewTest#testTextAlignmentDefault;android.widget.cts.TableLayoutTest#testCheckLayoutParams;android.widget.cts.AnalogClockTest#testOnSizeChanged;android.widget.cts.DialerFilterTest#testSetLettersWatcher;android.widget.cts.ViewAnimatorTest#testAccessDisplayedChildBoundary;android.widget.cts.TextViewTest#testSetSpannableFactory;android.widget.cts.ImageSwitcherTest#testConstructor;android.widget.cts.TextViewTest#testAccessMovementMethod;android.widget.cts.AbsSeekBarTest#testDrawableStateChanged;android.widget.cts.RadioGroupTest#testAddView;android.widget.cts.HorizontalScrollViewTest#testOnInterceptTouchEvent;android.widget.cts.TabHostTest#testConstructor;android.widget.cts.CursorTreeAdapterTest#testGetChildrenCount;android.widget.cts.SimpleCursorAdapterTest#testChangeCursor;android.widget.cts.HorizontalScrollViewTest#testAccessFillViewport;android.widget.cts.AbsSeekBarTest#testFoo;android.widget.cts.TableLayoutTest#testConstructor;android.widget.cts.GalleryTest#testSetUnselectedAlpha;android.widget.cts.AbsListViewTest#testInvalidateViews;android.widget.cts.HeaderViewListAdapterTest#testGetCount;android.widget.cts.RatingBarTest#testAccessIndicator;android.widget.cts.RelativeLayout_LayoutParamsTest#testConstructor;android.widget.cts.CursorAdapterTest#testNewDropDownView;android.widget.cts.ChronometerTest#testAccessFormat;android.widget.cts.ExpandableListViewBasicTest#testPreconditions;android.widget.cts.AbsListViewTest#testFoo;android.widget.cts.ListViewTest#testOnTouchEvent;android.widget.cts.TabHostTest#testAddTab;android.widget.cts.AdapterViewTest#testChangeFocusable;android.widget.cts.ListViewTest#testAccessDivider;android.widget.cts.ListViewTest#testAccessFooterView;android.widget.cts.SimpleCursorAdapterTest#testAccessViewBinder;android.widget.cts.ZoomButtonTest#testSetEnabled;android.widget.cts.CheckedTextViewTest#testConstructor;android.widget.cts.GridViewTest#testLayoutChildren;android.widget.cts.ImageViewTest#testSetAlpha;android.widget.cts.TextViewTest#testClearComposingText;android.widget.cts.ZoomControlsTest#testSetIsZoomInEnabled;android.widget.cts.TabWidgetTest#testConstructor;android.widget.cts.TableRowTest#testGenerateLayoutParams2;android.widget.cts.TextViewTest#testSetTextAppearance;android.widget.cts.FilterTest#testConvertResultToString;android.widget.cts.MultiAutoCompleteTextViewTest#testPerformValidation;android.widget.cts.TextViewTest#testHeightAndWidth;android.widget.cts.CursorTreeAdapterTest#testIsChildSelectable;android.widget.cts.ArrayAdapterTest#testAddAllCollection;android.widget.cts.AbsListView_LayoutParamsTest#testConstructors;android.widget.cts.ScrollViewTest#testDispatchKeyEvent;android.widget.cts.TabHostTest#testAccessCurrentTab;android.widget.cts.ViewSwitcherTest#testReset;android.widget.cts.TimePickerTest#testAccessIs24HourView;android.widget.cts.TextViewTest#testGetTotalPaddingTop;android.widget.cts.HorizontalScrollViewTest#testExecuteKeyEvent;android.widget.cts.AbsoluteLayoutTest#testOnLayout;android.widget.cts.ImageViewTest#testAccessScaleType;android.widget.cts.TabHostTest#testGetTabWidget;android.widget.cts.SlidingDrawerTest#testAnimateToggle;android.widget.cts.SlidingDrawerTest#testLockAndUnlock;android.widget.cts.GalleryTest#testSetGravity;android.widget.cts.ListViewTest#testOnFinishInflate;android.widget.cts.ScrollViewTest#testArrowScroll;android.widget.cts.ScrollViewTest#testComputeScrollDeltaToGetChildRectOnScreen;android.widget.cts.TabHostTest#testGetCurrentTabView;android.widget.cts.ExpandableListViewBasicTest#testExpandGroup;android.widget.cts.TextViewTest#testExtractText;android.widget.cts.RemoteViewsTest#testOnLoadClass;android.widget.cts.RadioGroupTest#testCheckLayoutParams;android.widget.cts.TextSwitcherTest#testSetText;android.widget.cts.AbsListViewTest#testGenerateLayoutParams;android.widget.cts.TabWidgetTest#testSetEnabled;android.widget.cts.AutoCompleteTextViewTest#testAccessItemClickListener;android.widget.cts.ChronometerTest#testFoo;android.widget.cts.ExpandableListViewBasicTest#testConvertionBetweenFlatAndPacked;android.widget.cts.DatePickerTest#testOnSaveInstanceState;android.widget.cts.DatePickerTest#testAndroidTestCaseSetupProperly;android.widget.cts.ImageButtonTest#testOnSetAlpha;android.widget.cts.AdapterViewTest#testAccessOnItemSelectedListener;android.widget.cts.BaseExpandableListAdapterTest#testOnGroupCollapsed;android.widget.cts.TableLayoutTest#testGenerateLayoutParams1;android.widget.cts.TableLayoutTest#testGenerateLayoutParams2;android.widget.cts.LinearLayoutTest#testLayoutVertical;android.widget.cts.CursorTreeAdapterTest#testAccessQueryProvider;android.widget.cts.TextViewTest#testSetTextKeepState1;android.widget.cts.ArrayAdapterTest#testConstructor;android.widget.cts.RemoteViewsTest#testDescribeContents;android.widget.cts.RelativeLayoutTest#testGenerateDefaultLayoutParams;android.widget.cts.SimpleExpandableListAdapterTest#testHasStableIds;android.widget.cts.TextViewTest#testOnPreDraw;android.widget.cts.ExpandableListViewBasicTest#testCollapseGroup;android.widget.cts.ExpandableListViewWithHeadersTest#testExpandOnFirstPosition;android.widget.cts.SimpleCursorAdapterTest#testSetViewText;android.widget.cts.RelativeLayoutTest#testSetIgnoreGravity;android.widget.cts.RadioGroup_LayoutParamsTest#testAndroidTestCaseSetupProperly;android.widget.cts.BaseAdapterTest#testAreAllItemsEnabled;android.widget.cts.RemoteViewsTest#testSetInt;android.widget.cts.AutoCompleteTextViewTest#testAccessDropDownAnchor;android.widget.cts.ScrollerTest#testIsFinished;android.widget.cts.TextViewTest#testAccessGravity;android.widget.cts.TableLayoutTest#testAccessColumnStretchable;android.widget.cts.ExpandableListViewTest#testSetOnGroupClickListener;android.widget.cts.AlphabetIndexerTest#testCompare;android.widget.cts.AbsListView_LayoutParamsTest#testAndroidTestCaseSetupProperly;android.widget.cts.LayoutDirectionTest#testLayoutDirectionDefaults;android.widget.cts.HeaderViewListAdapterTest#testAreAllItemsEnabled;android.widget.cts.LinearLayout_LayoutParamsTest#testDebug;android.widget.cts.CursorTreeAdapterTest#testGetCursor;android.widget.cts.ImageViewTest#testOnDraw;android.widget.cts.GalleryTest#testGetChildDrawingOrder;android.widget.cts.TextViewTest#testAccessInputExtras;android.widget.cts.LinearLayoutTest#testGetBaseline;android.widget.cts.RatingBarTest#testConstructor;android.widget.cts.RemoteViewsTest#testSetUri;android.widget.cts.SpinnerTest#testsetPromptId;android.widget.cts.RemoteViewsTest#testSetTextColor;android.widget.cts.VideoViewTest#testGetDuration;android.widget.cts.AdapterViewTest#testGetCount;android.widget.cts.MultiAutoCompleteTextView_CommaTokenizerTest#testFindTokenStart;android.widget.cts.ImageViewTest#testSetImageBitmap;android.widget.cts.HeaderViewListAdapterTest#testUnregisterDataSetObserver;android.widget.cts.PopupWindowTest#testAccessOutsideTouchable;android.widget.cts.EditTextTest#testSetEllipsize;android.widget.cts.SimpleAdapterTest#testGetCount;android.widget.cts.SpinnerTest#testSetOnItemClickListener;android.widget.cts.SlidingDrawerTest#testToggle;android.widget.cts.AbsSpinnerTest#testPointToPosition;android.widget.cts.ViewFlipperTest#testViewFlipper;android.widget.cts.TabHostTest#testDispatchKeyEvent;android.widget.cts.ExpandableListViewTest#testIsGroupExpanded;android.widget.cts.LayoutDirectionTest#testDirectionFromXml;android.widget.cts.TextViewTest#testVerifyDrawable;android.widget.cts.ProgressBarTest#testIncrementProgressBy;android.widget.cts.PopupWindowTest#testShowAsDropDown;android.widget.cts.ListViewTest#testCanAnimate;android.widget.cts.HorizontalScrollViewTest#testMeasureChild;android.widget.cts.RadioGroupTest#testClearCheck;android.widget.cts.SimpleAdapterTest#testConstructor;android.widget.cts.HorizontalScrollViewTest#testGetHorizontalFadingEdgeStrengths;android.widget.cts.CursorAdapterTest#testGetItem" />
</TestPlan>
diff --git a/tests/plans/CTS-stable.xml b/tests/plans/CTS-stable.xml
index b9e7321..d9d06d4 100644
--- a/tests/plans/CTS-stable.xml
+++ b/tests/plans/CTS-stable.xml
@@ -31,7 +31,7 @@
<Entry uri="android.gesture"/>
<Entry uri="android.graphics"/>
<Entry uri="android.graphics2"/>
- <Entry uri="android.hardware" exclude="android.hardware.cts.SensorIntegrationTests#testAccelerometerDoesNotStopGyroscope;android.hardware.cts.SensorIntegrationTests#testsAccelerometerDoesnNotStopMagnetometer;android.hardware.cts.SensorIntegrationTests#testAndroidTestCaseSetupProperly;android.hardware.cts.SensorIntegrationTests#testBatchAndFlush;android.hardware.cts.SensorIntegrationTests#testGyroscopeDoesNotStopAccelerometer;android.hardware.cts.SensorIntegrationTests#testGyroscopeDoesNotStopMagnetometer;android.hardware.cts.SensorIntegrationTests#testMagnetometerDoesNotStopAccelerometer;android.hardware.cts.SensorIntegrationTests#testMagnetometerDoesNotStopGyroscope;android.hardware.cts.SensorMagneticFieldTest#testBatchingStoppingOtherClients;android.hardware.cts.SensorMagneticFieldTest#testBatchingStoppingOtherClientsBatching;android.hardware.cts.SensorMagneticFieldTest#testFrequencyAccuracy;android.hardware.cts.SensorMagneticFieldTest#testOneClientSeveralThreads;android.hardware.cts.SensorMagneticFieldTest#testOneClientSeveralThreadsBatching;android.hardware.cts.SensorMagneticFieldTest#testStandardDeviationWhileStatic;android.hardware.cts.SensorMagneticFieldTest#testStoppingOtherClients;android.hardware.cts.SensorMagneticFieldTest#testStoppingOtherClientsBatching;android.hardware.cts.SensorAccelerometerTest#testBatchingStoppingOtherClients;android.hardware.cts.SensorAccelerometerTest#testBatchingStoppingOtherClientsBatching;android.hardware.cts.SensorAccelerometerTest#testFrequencyAccuracy;android.hardware.cts.SensorAccelerometerTest#testOneClientSeveralThreads;android.hardware.cts.SensorAccelerometerTest#testOneClientSeveralThreadsBatching;android.hardware.cts.SensorGyroscopeTest#testBatchingStoppingOtherClients;android.hardware.cts.SensorGyroscopeTest#testBatchingStoppingOtherClientsBatching;android.hardware.cts.SensorGyroscopeTest#testFrequencyAccuracy;android.hardware.cts.SensorGyroscopeTest#testOneClientSeveralThreads;android.hardware.cts.SensorGyroscopeTest#testOneClientSeveralThreadsBatching;android.hardware.cts.SensorGyroscopeTest#testStandardDeviationWhilStatic;android.hardware.cts.SensorGyroscopeTest#testStoppingOtherClients;android.hardware.cts.SensorGyroscopeTest#testStoppingOtherClientsBatching;android.hardware.cts.SensorAccelerometerTest#testStandardDeviationWhileStatic;android.hardware.cts.SensorAccelerometerTest#testStoppingOtherClients;android.hardware.cts.SensorAccelerometerTest#testStoppingOtherClientsBatching;android.hardware.camera2.cts.CameraDeviceTest#testCameraDeviceRepeatingRequest;android.hardware.camera2.cts.ImageReaderTest#testImageReaderFromCameraJpeg;android.hardware.cts.CameraGLTest#testCameraToSurfaceTextureMetadata;android.hardware.cts.CameraTest#testImmediateZoom;android.hardware.cts.CameraTest#testPreviewCallback;android.hardware.cts.CameraTest#testSmoothZoom;android.hardware.cts.CameraTest#testVideoSnapshot;android.hardware.cts.CameraGLTest#testSetPreviewTextureBothCallbacks;android.hardware.cts.CameraGLTest#testSetPreviewTexturePreviewCallback" />
+ <Entry uri="android.hardware" exclude="android.hardware.camera2.cts.CameraDeviceTest#testCameraDeviceRepeatingRequest;android.hardware.camera2.cts.ImageReaderTest#testImageReaderFromCameraJpeg;android.hardware.cts.CameraGLTest#testCameraToSurfaceTextureMetadata;android.hardware.cts.CameraTest#testImmediateZoom;android.hardware.cts.CameraTest#testPreviewCallback;android.hardware.cts.CameraTest#testSmoothZoom;android.hardware.cts.CameraTest#testVideoSnapshot;android.hardware.cts.CameraGLTest#testSetPreviewTextureBothCallbacks;android.hardware.cts.CameraGLTest#testSetPreviewTexturePreviewCallback" />
<Entry uri="android.holo"/>
<Entry uri="android.jni"/>
<Entry uri="android.keystore"/>
@@ -50,7 +50,7 @@
<Entry uri="android.permission2"/>
<Entry uri="android.preference"/>
<Entry uri="android.preference2"/>
- <Entry uri="android.provider" exclude="android.provider.cts.CalendarTest#testRemindersAlarm" />
+ <Entry uri="android.provider"/>
<Entry uri="android.renderscript"/>
<Entry uri="android.rscpp"/>
<Entry uri="android.rsg"/>
@@ -59,7 +59,7 @@
<Entry uri="android.speech"/>
<Entry uri="android.telephony"/>
<Entry uri="android.tests.appsecurity"/>
- <Entry uri="android.tests.location"/>
+ <Entry uri="android.tests.location"/>
<Entry uri="android.tests.sigtest"/>
<Entry uri="android.text"/>
<Entry uri="android.textureview"/>
@@ -69,7 +69,7 @@
<Entry uri="android.util"/>
<Entry uri="android.view"/>
<Entry uri="android.webkit" exclude="android.webkit.cts.WebViewClientTest#testDoUpdateVisitedHistory;android.webkit.cts.WebViewClientTest#testLoadPage;android.webkit.cts.WebViewClientTest#testOnFormResubmission;android.webkit.cts.WebViewClientTest#testOnReceivedError;android.webkit.cts.WebViewClientTest#testOnReceivedHttpAuthRequest;android.webkit.cts.WebViewClientTest#testOnScaleChanged;android.webkit.cts.WebViewClientTest#testOnUnhandledKeyEvent;android.webkit.cts.WebViewTest#testSetInitialScale" />
- <Entry uri="android.widget" exclude="android.widget.cts.GridViewTest#testSetNumColumns" />
+ <Entry uri="android.widget"/>
<Entry uri="com.android.cts.bootup"/>
<Entry uri="com.android.cts.browserbench"/>
<Entry uri="com.android.cts.dram"/>
diff --git a/tests/print/Android.mk b/tests/print/Android.mk
new file mode 100644
index 0000000..fea7dc0
--- /dev/null
+++ b/tests/print/Android.mk
@@ -0,0 +1,36 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+##################################################
+# Build the print instrument library
+##################################################
+include $(CLEAR_VARS)
+LOCAL_MODULE := CtsPrintInstrument
+LOCAL_SRC_FILES := $(call all-subdir-java-files) \
+ src/android/print/cts/IPrivilegedOperations.aidl
+LOCAL_MODULE_TAGS := optional
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_JAVA_LIBRARY)
+
+# Copy the shell script to run the print instrument Jar to the CTS out folder.
+$(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).jar : $(LOCAL_BUILT_MODULE) | $(ACP)
+ $(copy-file-to-target)
+
+# Copy the built print instrument library Jar to the CTS out folder.
+$(CTS_TESTCASES_OUT)/print-instrument : $(LOCAL_PATH)/print-instrument | $(ACP)
+ $(copy-file-to-target)
+
diff --git a/tests/print/print-instrument b/tests/print/print-instrument
new file mode 100755
index 0000000..a79cb8a
--- /dev/null
+++ b/tests/print/print-instrument
@@ -0,0 +1,37 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Script to start "print-instrument" on the device
+#
+# The script sets up an alternative dalvik cache when running as
+# non-root. Jar files needs to be dexopt'd to run in Dalvik. For
+# plain jar files, this is done at first use. shell user does not
+# have write permission to default system Dalvik cache so we
+# redirect to an alternative cache.
+
+RUN_BASE=/data/local/tmp
+
+# If not running as root, use an alternative dex cache.
+if [ ${USER_ID} -ne 0 ]; then
+ tmp_cache=${RUN_BASE}/dalvik-cache
+ if [ ! -d ${tmp_cache} ]; then
+ mkdir -p ${tmp_cache}
+ fi
+ export ANDROID_DATA=${RUN_BASE}
+fi
+
+# Run print-instrument.
+export CLASSPATH=${RUN_BASE}/CtsPrintInstrument.jar
+
+exec app_process ${RUN_BASE} android.print.cts.PrintInstrument ${@}
diff --git a/tests/print/src/android/print/cts/IPrivilegedOperations.aidl b/tests/print/src/android/print/cts/IPrivilegedOperations.aidl
new file mode 100644
index 0000000..93c8c3e
--- /dev/null
+++ b/tests/print/src/android/print/cts/IPrivilegedOperations.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.cts;
+
+interface IPrivilegedOperations {
+ boolean clearApplicationUserData(String packageName);
+}
diff --git a/tests/print/src/android/print/cts/PrintInstrument.java b/tests/print/src/android/print/cts/PrintInstrument.java
new file mode 100644
index 0000000..cd07410
--- /dev/null
+++ b/tests/print/src/android/print/cts/PrintInstrument.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.cts;
+
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.app.IInstrumentationWatcher;
+import android.app.Instrumentation;
+import android.app.UiAutomationConnection;
+import android.content.ComponentName;
+import android.content.pm.IPackageDataObserver;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.AndroidException;
+import android.view.IWindowManager;
+
+import com.android.internal.os.BaseCommand;
+
+import java.io.PrintStream;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public final class PrintInstrument extends BaseCommand {
+
+ private static final String ARG_PRIVILEGED_OPS = "ARG_PRIVILEGED_OPS";
+
+ private IActivityManager mAm;
+
+ public static void main(String[] args) {
+ PrintInstrument instrumenter = new PrintInstrument();
+ instrumenter.run(args);
+ }
+
+ @Override
+ public void onRun() throws Exception {
+ mAm = ActivityManagerNative.getDefault();
+ if (mAm == null) {
+ System.err.println(NO_SYSTEM_ERROR_CODE);
+ throw new AndroidException("Can't connect to activity manager;"
+ + " is the system running?");
+ }
+
+ String op = nextArgRequired();
+
+ if (op.equals("instrument")) {
+ runInstrument();
+ } else {
+ showError("Error: unknown command '" + op + "'");
+ }
+ }
+
+ @Override
+ public void onShowUsage(PrintStream out) {
+ /* do nothing */
+ }
+
+ @SuppressWarnings("deprecation")
+ private void runInstrument() throws Exception {
+ String profileFile = null;
+ boolean wait = false;
+ boolean rawMode = false;
+ boolean no_window_animation = false;
+ int userId = UserHandle.USER_CURRENT;
+ Bundle args = new Bundle();
+ String argKey = null, argValue = null;
+ IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
+
+ String opt;
+ while ((opt=nextOption()) != null) {
+ if (opt.equals("-p")) {
+ profileFile = nextArgRequired();
+ } else if (opt.equals("-w")) {
+ wait = true;
+ } else if (opt.equals("-r")) {
+ rawMode = true;
+ } else if (opt.equals("-e")) {
+ argKey = nextArgRequired();
+ argValue = nextArgRequired();
+ args.putString(argKey, argValue);
+ } else if (opt.equals("--no_window_animation")
+ || opt.equals("--no-window-animation")) {
+ no_window_animation = true;
+ } else if (opt.equals("--user")) {
+ userId = parseUserArg(nextArgRequired());
+ } else {
+ System.err.println("Error: Unknown option: " + opt);
+ return;
+ }
+ }
+
+ if (userId == UserHandle.USER_ALL) {
+ System.err.println("Error: Can't start instrumentation with user 'all'");
+ return;
+ }
+
+ String cnArg = nextArgRequired();
+ ComponentName cn = ComponentName.unflattenFromString(cnArg);
+ if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg);
+
+ InstrumentationWatcher watcher = null;
+ UiAutomationConnection connection = null;
+ if (wait) {
+ watcher = new InstrumentationWatcher();
+ watcher.setRawOutput(rawMode);
+ connection = new UiAutomationConnection();
+ }
+
+ float[] oldAnims = null;
+ if (no_window_animation) {
+ oldAnims = wm.getAnimationScales();
+ wm.setAnimationScale(0, 0.0f);
+ wm.setAnimationScale(1, 0.0f);
+ }
+
+ args.putIBinder(ARG_PRIVILEGED_OPS, new PrivilegedOperations(mAm));
+
+ if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId)) {
+ throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
+ }
+
+ if (watcher != null) {
+ if (!watcher.waitForFinish()) {
+ System.out.println("INSTRUMENTATION_ABORTED: System has crashed.");
+ }
+ }
+
+ if (oldAnims != null) {
+ wm.setAnimationScales(oldAnims);
+ }
+ }
+
+ private int parseUserArg(String arg) {
+ int userId;
+ if ("all".equals(arg)) {
+ userId = UserHandle.USER_ALL;
+ } else if ("current".equals(arg) || "cur".equals(arg)) {
+ userId = UserHandle.USER_CURRENT;
+ } else {
+ userId = Integer.parseInt(arg);
+ }
+ return userId;
+ }
+
+ private class InstrumentationWatcher extends IInstrumentationWatcher.Stub {
+ private boolean mFinished = false;
+ private boolean mRawMode = false;
+
+ /**
+ * Set or reset "raw mode". In "raw mode", all bundles are dumped. In "pretty mode",
+ * if a bundle includes Instrumentation.REPORT_KEY_STREAMRESULT, just print that.
+ * @param rawMode true for raw mode, false for pretty mode.
+ */
+ public void setRawOutput(boolean rawMode) {
+ mRawMode = rawMode;
+ }
+
+ @Override
+ public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) {
+ synchronized (this) {
+ // pretty printer mode?
+ String pretty = null;
+ if (!mRawMode && results != null) {
+ pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
+ }
+ if (pretty != null) {
+ System.out.print(pretty);
+ } else {
+ if (results != null) {
+ for (String key : results.keySet()) {
+ System.out.println(
+ "INSTRUMENTATION_STATUS: " + key + "=" + results.get(key));
+ }
+ }
+ System.out.println("INSTRUMENTATION_STATUS_CODE: " + resultCode);
+ }
+ notifyAll();
+ }
+ }
+
+ @Override
+ public void instrumentationFinished(ComponentName name, int resultCode,
+ Bundle results) {
+ synchronized (this) {
+ // pretty printer mode?
+ String pretty = null;
+ if (!mRawMode && results != null) {
+ pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
+ }
+ if (pretty != null) {
+ System.out.println(pretty);
+ } else {
+ if (results != null) {
+ for (String key : results.keySet()) {
+ System.out.println(
+ "INSTRUMENTATION_RESULT: " + key + "=" + results.get(key));
+ }
+ }
+ System.out.println("INSTRUMENTATION_CODE: " + resultCode);
+ }
+ mFinished = true;
+ notifyAll();
+ }
+ }
+
+ public boolean waitForFinish() {
+ synchronized (this) {
+ while (!mFinished) {
+ try {
+ if (!mAm.asBinder().pingBinder()) {
+ return false;
+ }
+ wait(1000);
+ } catch (InterruptedException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+ return true;
+ }
+ }
+
+ private static final class PrivilegedOperations extends IPrivilegedOperations.Stub {
+ private final IActivityManager mAm;
+
+ public PrivilegedOperations(IActivityManager am) {
+ mAm = am;
+ }
+
+ @Override
+ public boolean clearApplicationUserData(final String clearedPackageName)
+ throws RemoteException {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ final AtomicBoolean success = new AtomicBoolean();
+ final CountDownLatch completionLacth = new CountDownLatch(1);
+
+ mAm.clearApplicationUserData(clearedPackageName,
+ new IPackageDataObserver.Stub() {
+ @Override
+ public void onRemoveCompleted(String packageName, boolean succeeded) {
+ if (clearedPackageName.equals(packageName) && succeeded) {
+ success.set(true);
+ } else {
+ success.set(false);
+ }
+ completionLacth.countDown();
+ }
+ }, UserHandle.USER_CURRENT);
+
+ try {
+ completionLacth.await();
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+
+ return success.get();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+}
diff --git a/tests/res/layout/inflater_override_theme_layout.xml b/tests/res/layout/inflater_override_theme_layout.xml
new file mode 100644
index 0000000..4440f7c
--- /dev/null
+++ b/tests/res/layout/inflater_override_theme_layout.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2013 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:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ theme="@style/Theme_OverrideOuter"
+ android:orientation="vertical" >
+
+ <View
+ android:id="@+id/view_outer"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ theme="@style/Theme_OverrideInner"
+ android:orientation="vertical" >
+
+ <View
+ android:id="@+id/view_inner"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </LinearLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/res/layout/surface_view_2.xml b/tests/res/layout/surface_view_2.xml
new file mode 100644
index 0000000..fe53c71
--- /dev/null
+++ b/tests/res/layout/surface_view_2.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <SurfaceView
+ android:id="@+id/surface_view"
+ android:layout_width="320dp"
+ android:layout_height="240dp"/>
+
+</LinearLayout>
diff --git a/tests/res/values/attrs.xml b/tests/res/values/attrs.xml
index 9793893..0525cae 100644
--- a/tests/res/values/attrs.xml
+++ b/tests/res/values/attrs.xml
@@ -125,4 +125,6 @@
<attr name="textColorHint"/>
<attr name="textColorLink"/>
</declare-styleable>
+ <!-- Integer used to uniquely identify theme overrides. -->
+ <attr name="themeType" format="integer"/>
</resources>
diff --git a/tests/res/values/styles.xml b/tests/res/values/styles.xml
index f8b56fd..047e97c 100644
--- a/tests/res/values/styles.xml
+++ b/tests/res/values/styles.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<resources>
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="Whatever">
<item name="type1">true</item>
@@ -138,4 +138,12 @@
<item name="android:panelColorBackground">#ffffffff</item>
</style>
+ <style name="Theme_OverrideOuter">
+ <item name="themeType">1</item>
+ </style>
+
+ <style name="Theme_OverrideInner">
+ <item name="themeType">2</item>
+ </style>
+
</resources>
diff --git a/tests/src/android/hardware/camera2/cts/Camera2SurfaceViewStubActivity.java b/tests/src/android/hardware/camera2/cts/Camera2SurfaceViewStubActivity.java
new file mode 100644
index 0000000..47b4cba
--- /dev/null
+++ b/tests/src/android/hardware/camera2/cts/Camera2SurfaceViewStubActivity.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.ConditionVariable;
+import android.util.Log;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import com.android.cts.stub.R;
+
+public class Camera2SurfaceViewStubActivity extends Activity implements SurfaceHolder.Callback {
+ private final static String TAG = "Camera2SurfaceViewStubActivity";
+ private final ConditionVariable surfaceChangedDone = new ConditionVariable();
+
+ private SurfaceView mSurfaceView;
+ private int currentWidth = 0;
+ private int currentHeight = 0;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.surface_view_2);
+ mSurfaceView = (SurfaceView) findViewById(R.id.surface_view);
+ mSurfaceView.getHolder().addCallback(this);
+ }
+
+ public SurfaceView getSurfaceView() {
+ return mSurfaceView;
+ }
+
+ public boolean waitForSurfaceSizeChanged(int timeOutMs, int expectWidth, int expectHeight) {
+ if (timeOutMs <= 0 || expectWidth <= 0 || expectHeight <= 0) {
+ throw new IllegalArgumentException(
+ String.format(
+ "timeout(%d), expectWidth(%d), and expectHeight(%d) " +
+ "should all be positive numbers",
+ timeOutMs, expectWidth, expectHeight));
+ }
+
+ int waitTimeMs = timeOutMs;
+ boolean changeSucceeded = false;
+ while (!changeSucceeded && waitTimeMs > 0) {
+ long startTimeMs = System.currentTimeMillis();
+ changeSucceeded = surfaceChangedDone.block(waitTimeMs);
+ if (!changeSucceeded) {
+ Log.e(TAG, "Wait for surface change timed out after " + timeOutMs + " ms");
+ return changeSucceeded;
+ } else {
+ // Get a surface change callback, need to check if the size is expected.
+ surfaceChangedDone.close();
+ if (currentWidth == expectWidth && currentHeight == expectHeight) {
+ return changeSucceeded;
+ }
+ // Do a further iteration surface change check as surfaceChanged could be called
+ // again.
+ changeSucceeded = false;
+ }
+ waitTimeMs -= (System.currentTimeMillis() - startTimeMs);
+ }
+
+ // Couldn't get expected surface size change.
+ return false;
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ Log.i(TAG, "Surface Changed to: " + width + "x" + height);
+ currentWidth = width;
+ currentHeight = height;
+ surfaceChangedDone.open();
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ }
+}
diff --git a/tests/src/android/webkit/cts/WebViewOnUiThread.java b/tests/src/android/webkit/cts/WebViewOnUiThread.java
index 3616655..715af12 100644
--- a/tests/src/android/webkit/cts/WebViewOnUiThread.java
+++ b/tests/src/android/webkit/cts/WebViewOnUiThread.java
@@ -685,6 +685,15 @@
});
}
+ public WebView createWebView() {
+ return getValue(new ValueGetter<WebView>() {
+ @Override
+ public WebView capture() {
+ return new WebView(mWebView.getContext());
+ }
+ });
+ }
+
public PrintDocumentAdapter createPrintDocumentAdapter() {
return getValue(new ValueGetter<PrintDocumentAdapter>() {
@Override
diff --git a/tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java b/tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java
index 3aaf54e..7862cb4 100644
--- a/tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java
+++ b/tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityRecordTest.java
@@ -204,7 +204,7 @@
static void assertNoNewNonStaticFieldsAdded(Class<?> clazz, int expectedCount) {
int nonStaticFieldCount = 0;
- while (clazz != null) {
+ while (clazz != Object.class) {
for (Field field : clazz.getDeclaredFields()) {
if ((field.getModifiers() & Modifier.STATIC) == 0) {
nonStaticFieldCount++;
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java
index c981db3..5ef710f 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java
@@ -88,7 +88,7 @@
private int mMseMargin = 3 * (1 * 1);
// MSE margin for WebP Region-Decoding for 'Config.RGB_565' is little bigger.
- private int mMseMarginWebPConfigRgb565 = 5;
+ private int mMseMarginWebPConfigRgb565 = 8;
@Override
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerTest.java
index 0672db6..26cdbb6 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerTest.java
@@ -186,10 +186,10 @@
assertConstantStateNotSet();
assertNull(mDrawableContainer.getCurrent());
+ mDrawableContainer.setConstantState(mDrawableContainerState);
mDrawableContainer.setColorFilter(null);
mDrawableContainer.setColorFilter(new ColorFilter());
- mDrawableContainer.setConstantState(mDrawableContainerState);
MockDrawable dr = new MockDrawable();
addAndSelectDrawable(dr);
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraCaptureResultTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraCaptureResultTest.java
index 6a708e3..c56626b 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraCaptureResultTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraCaptureResultTest.java
@@ -274,6 +274,7 @@
ArrayList<CameraMetadata.Key<?>> resultKeys = new ArrayList<CameraMetadata.Key<?>>();
resultKeys.add(CaptureResult.COLOR_CORRECTION_TRANSFORM);
resultKeys.add(CaptureResult.COLOR_CORRECTION_GAINS);
+ resultKeys.add(CaptureResult.CONTROL_AE_MODE);
resultKeys.add(CaptureResult.CONTROL_AE_REGIONS);
resultKeys.add(CaptureResult.CONTROL_AF_MODE);
resultKeys.add(CaptureResult.CONTROL_AF_REGIONS);
@@ -309,13 +310,7 @@
resultKeys.add(CaptureResult.SENSOR_TIMESTAMP);
resultKeys.add(CaptureResult.SENSOR_TEMPERATURE);
resultKeys.add(CaptureResult.STATISTICS_FACE_DETECT_MODE);
- resultKeys.add(CaptureResult.STATISTICS_FACE_IDS);
- resultKeys.add(CaptureResult.STATISTICS_FACE_LANDMARKS);
- resultKeys.add(CaptureResult.STATISTICS_FACE_RECTANGLES);
- resultKeys.add(CaptureResult.STATISTICS_FACE_SCORES);
resultKeys.add(CaptureResult.STATISTICS_LENS_SHADING_MAP);
- resultKeys.add(CaptureResult.STATISTICS_PREDICTED_COLOR_GAINS);
- resultKeys.add(CaptureResult.STATISTICS_PREDICTED_COLOR_TRANSFORM);
resultKeys.add(CaptureResult.STATISTICS_SCENE_FLICKER);
resultKeys.add(CaptureResult.TONEMAP_CURVE_BLUE);
resultKeys.add(CaptureResult.TONEMAP_CURVE_GREEN);
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraCharacteristicsTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraCharacteristicsTest.java
index 1b892ba..09d5b90 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraCharacteristicsTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraCharacteristicsTest.java
@@ -80,6 +80,29 @@
}
}
+ public void testCameraCharacteristicsAndroidControlAeAvailableModes() throws Exception {
+ String[] ids = mCameraManager.getCameraIdList();
+ for (int i = 0; i < ids.length; i++) {
+ CameraCharacteristics props = mCameraManager.getCameraCharacteristics(ids[i]);
+ assertNotNull(String.format("Can't get camera characteristics from: ID %s", ids[i]),
+ props);
+
+ {
+
+ assertNotNull("Invalid property: android.control.aeAvailableModes",
+ props.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES));
+
+ List<Key<?>> allKeys = props.getKeys();
+ assertNotNull(String.format("Can't get camera characteristics keys from: ID %s",
+ ids[i], props));
+ assertTrue("Key not in keys list: android.control.aeAvailableModes", allKeys.contains(
+ CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES));
+
+ }
+
+ }
+ }
+
public void testCameraCharacteristicsAndroidControlAeAvailableTargetFpsRanges() throws Exception {
String[] ids = mCameraManager.getCameraIdList();
for (int i = 0; i < ids.length; i++) {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
index f68b10a..0f05816 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
@@ -22,7 +22,6 @@
import android.content.Context;
import android.graphics.ImageFormat;
-import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
@@ -32,6 +31,7 @@
import android.media.Image;
import android.media.ImageReader;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.SystemClock;
import android.test.AndroidTestCase;
import android.util.Log;
@@ -52,19 +52,11 @@
private CameraManager mCameraManager;
private BlockingStateListener mCameraListener;
- private CameraTestThread mLooperThread;
+ private HandlerThread mHandlerThread;
private Handler mCallbackHandler;
private int mLatestState = STATE_UNINITIALIZED;
- /**
- * The error triggered flag starts out as false, and it will flip to true if any errors
- * are ever caught; it won't be reset to false after that happens. This is due to the
- * fact that when multiple tests are run back to back (as they are here), it's hard
- * to associate the asynchronous error with the test that caused it (so we won't even try).
- */
- private boolean mErrorTriggered = false;
private ImageReader mReader;
- private CameraTestThread mDummyThread;
private Surface mSurface;
private static final int CAMERA_CONFIGURE_TIMEOUT_MS = 2000;
@@ -120,14 +112,15 @@
mCameraManager = (CameraManager)mContext.getSystemService(Context.CAMERA_SERVICE);
assertNotNull("Can't connect to camera manager", mCameraManager);
+ mHandlerThread = new HandlerThread(TAG);
+ mHandlerThread.start();
+ mCallbackHandler = new Handler(mHandlerThread.getLooper());
createDefaultSurface();
- mLooperThread = new CameraTestThread();
- mCallbackHandler = mLooperThread.start();
}
@Override
protected void tearDown() throws Exception {
- mDummyThread.close();
+ mHandlerThread.quitSafely();
mReader.close();
super.tearDown();
}
@@ -401,8 +394,7 @@
mSurface = mReader.getSurface();
// Create dummy image listener since we don't care the image data in this test.
ImageReader.OnImageAvailableListener listener = new ImageDropperListener();
- mDummyThread = new CameraTestThread();
- mReader.setOnImageAvailableListener(listener, mDummyThread.start());
+ mReader.setOnImageAvailableListener(listener, mCallbackHandler);
}
private void waitForState(int state, long timeout) {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraManagerTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraManagerTest.java
index 7091cac..d64d47f 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraManagerTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraManagerTest.java
@@ -23,6 +23,7 @@
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.os.Handler;
+import android.os.HandlerThread;
import android.test.AndroidTestCase;
import android.util.Log;
@@ -40,7 +41,7 @@
private PackageManager mPackageManager;
private CameraManager mCameraManager;
private NoopCameraListener mListener;
- private CameraTestThread mLooperThread;
+ private HandlerThread mHandlerThread;
private Handler mHandler;
@Override
@@ -57,13 +58,14 @@
protected void setUp() throws Exception {
super.setUp();
- mLooperThread = new CameraTestThread();
- mHandler = mLooperThread.start();
+ mHandlerThread = new HandlerThread(TAG);
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
}
@Override
protected void tearDown() throws Exception {
- mLooperThread.close();
+ mHandlerThread.quitSafely();
mHandler = null;
super.tearDown();
@@ -252,12 +254,9 @@
* a listener that isn't registered should have no effect.
*/
public void testCameraManagerListener() throws Exception {
- CameraTestThread callbackThread = new CameraTestThread();
- Handler callbackHandler = callbackThread.start();
-
mCameraManager.removeAvailabilityListener(mListener);
- mCameraManager.addAvailabilityListener(mListener, callbackHandler);
- mCameraManager.addAvailabilityListener(mListener, callbackHandler);
+ mCameraManager.addAvailabilityListener(mListener, mHandler);
+ mCameraManager.addAvailabilityListener(mListener, mHandler);
mCameraManager.removeAvailabilityListener(mListener);
mCameraManager.removeAvailabilityListener(mListener);
}
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraSurfaceViewPreviewTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraSurfaceViewPreviewTest.java
new file mode 100644
index 0000000..1e3764e
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraSurfaceViewPreviewTest.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.cts;
+
+import static android.hardware.camera2.cts.CameraTestUtils.*;
+import static com.android.ex.camera2.blocking.BlockingStateListener.*;
+
+import android.content.Context;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraDevice.CaptureListener;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.Size;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+import android.view.SurfaceHolder;
+import android.view.Surface;
+
+import com.android.ex.camera2.blocking.BlockingStateListener;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
+import static org.mockito.Mockito.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * CameraDevice capture use case tests, including preview, still capture, burst
+ * capture etc.
+ */
+public class CameraSurfaceViewPreviewTest
+ extends ActivityInstrumentationTestCase2<Camera2SurfaceViewStubActivity> {
+ // Can not use class name exactly as it exceed the log tag character limit.
+ private static final String TAG = "CameraPreviewTest";
+ private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+ private static final int WAIT_FOR_SURFACE_CHANGE_TIMEOUT_MS = 1000;
+ private static final int FRAME_TIMEOUT_MS = 500;
+ private static final int NUM_FRAMES_VERIFIED = 30;
+
+ private Context mContext;
+ private CameraManager mCameraManager;
+ private String[] mCameraIds;
+ private CameraDevice mCamera;
+ private HandlerThread mHandlerThread;
+ private Handler mHandler;
+ private BlockingStateListener mCameraListener;
+
+ public CameraSurfaceViewPreviewTest() {
+ super(Camera2SurfaceViewStubActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mContext = getActivity();
+ mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
+ assertNotNull("Unable to get CameraManager", mCameraManager);
+ mCameraIds = mCameraManager.getCameraIdList();
+ assertNotNull("Unable to get camera ids", mCameraIds);
+ mHandlerThread = new HandlerThread(TAG);
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+ mCameraListener = new BlockingStateListener();
+
+ /**
+ * Workaround for mockito and JB-MR2 incompatibility
+ *
+ * Avoid java.lang.IllegalArgumentException: dexcache == null
+ * https://code.google.com/p/dexmaker/issues/detail?id=2
+ */
+ System.setProperty("dexmaker.dexcache", mContext.getCacheDir().toString());
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mHandlerThread.quitSafely();
+ mHandler = null;
+ mCameraListener = null;
+ super.tearDown();
+ }
+
+ public void testCameraPreview() throws Exception {
+ for (int i = 0; i < mCameraIds.length; i++) {
+ try {
+ Log.i(TAG, "Testing preview for Camera " + mCameraIds[i]);
+ mCamera = openCamera(mCameraManager, mCameraIds[i], mCameraListener, mHandler);
+ assertNotNull(
+ String.format("Failed to open camera device ID: %s", mCameraIds[i]),
+ mCamera);
+ previewTestByCamera();
+ } finally {
+ if (mCamera != null) {
+ mCamera.close();
+ mCamera = null;
+ }
+ }
+ }
+ }
+
+ /**
+ * Test all supported preview sizes for a camera device
+ *
+ * @throws Exception
+ */
+ private void previewTestByCamera() throws Exception {
+ List<Size> previewSizes = getSupportedPreviewSizes(
+ mCamera.getId(), mCameraManager, PREVIEW_SIZE_BOUND);
+ Camera2SurfaceViewStubActivity stubActivity = getActivity();
+
+ for (final Size sz : previewSizes) {
+ if (VERBOSE) {
+ Log.v(TAG, "Testing camera preview size: " + sz.toString());
+ }
+ // Change the preview size
+ final SurfaceHolder holder = stubActivity.getSurfaceView().getHolder();
+ Handler handler = new Handler(Looper.getMainLooper());
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ holder.setFixedSize(sz.getWidth(), sz.getHeight());
+ }
+ });
+
+ boolean res = stubActivity.waitForSurfaceSizeChanged(
+ WAIT_FOR_SURFACE_CHANGE_TIMEOUT_MS, sz.getWidth(), sz.getHeight());
+ assertTrue("wait for surface change to " + sz.toString() + " timed out", res);
+ Surface previewSurface = holder.getSurface();
+ assertTrue("Preview surface is invalid", previewSurface.isValid());
+
+ CaptureListener mockCaptureListener =
+ mock(CameraDevice.CaptureListener.class);
+
+ startPreview(previewSurface, mockCaptureListener);
+
+ verifyCaptureResults(mCamera, mockCaptureListener, NUM_FRAMES_VERIFIED,
+ NUM_FRAMES_VERIFIED * FRAME_TIMEOUT_MS);
+
+ stopPreview();
+ }
+ }
+
+ private void startPreview(Surface surface, CaptureListener listener) throws Exception {
+ List<Surface> outputSurfaces = new ArrayList<Surface>(/*capacity*/1);
+ outputSurfaces.add(surface);
+ mCamera.configureOutputs(outputSurfaces);
+ mCameraListener.waitForState(STATE_BUSY, CAMERA_BUSY_TIMEOUT_MS);
+ mCameraListener.waitForState(STATE_IDLE, CAMERA_IDLE_TIMEOUT_MS);
+
+ // TODO: vary the different settings like crop region to cover more cases.
+ CaptureRequest.Builder captureBuilder =
+ mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+
+ captureBuilder.addTarget(surface);
+ mCamera.setRepeatingRequest(captureBuilder.build(), listener, mHandler);
+ }
+
+ private void stopPreview() throws Exception {
+ if (VERBOSE) Log.v(TAG, "Stopping preview and waiting for idle");
+ // Stop repeat, wait for captures to complete, and disconnect from surfaces
+ mCamera.configureOutputs(/*outputs*/ null);
+ mCameraListener.waitForState(STATE_BUSY, CAMERA_BUSY_TIMEOUT_MS);
+ mCameraListener.waitForState(STATE_UNCONFIGURED, CAMERA_IDLE_TIMEOUT_MS);
+ }
+
+ private class IsCaptureResultValid extends ArgumentMatcher<CaptureResult> {
+ @Override
+ public boolean matches(Object obj) {
+ CaptureResult result = (CaptureResult)obj;
+ Long timeStamp = result.get(CaptureResult.SENSOR_TIMESTAMP);
+ if (timeStamp != null && timeStamp.longValue() > 0L) {
+ return true;
+ }
+ return false;
+ }
+ }
+
+ private void verifyCaptureResults(
+ CameraDevice camera,
+ CameraDevice.CaptureListener mockListener,
+ int expectResultCount,
+ int timeOutMs) {
+ // Should receive expected number of onCaptureStarted callbacks.
+ ArgumentCaptor<Long> timestamps = ArgumentCaptor.forClass(Long.class);
+ verify(mockListener,
+ timeout(timeOutMs).atLeast(expectResultCount))
+ .onCaptureStarted(
+ eq(camera),
+ isA(CaptureRequest.class),
+ timestamps.capture());
+
+ // Validate timestamps: all timestamps should be larger than 0 and monotonically increase.
+ long timestamp = 0;
+ for (Long nextTimestamp : timestamps.getAllValues()) {
+ Log.v(TAG, "next t: " + nextTimestamp + " current t: " + timestamp);
+ assertTrue("Captures are out of order", timestamp < nextTimestamp);
+ timestamp = nextTimestamp;
+ }
+
+ // Should receive expected number of capture results.
+ verify(mockListener,
+ timeout(timeOutMs).atLeast(expectResultCount))
+ .onCaptureCompleted(
+ eq(camera),
+ isA(CaptureRequest.class),
+ argThat(new IsCaptureResultValid()));
+
+ // Should not receive any capture failed callbacks.
+ verify(mockListener, never())
+ .onCaptureFailed(
+ eq(camera),
+ isA(CaptureRequest.class),
+ isA(CaptureFailure.class));
+ }
+
+}
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestThread.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestThread.java
deleted file mode 100644
index 9516ead..0000000
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestThread.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2013 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.hardware.camera2.cts;
-
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Log;
-
-import java.util.concurrent.TimeoutException;
-
-/**
- * Camera test thread wrapper for handling camera callbacks
- */
-public class CameraTestThread implements AutoCloseable {
- private static final String TAG = "CameraTestThread";
- private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
- // Timeout for initializing looper and opening camera in Milliseconds.
- private static final long WAIT_FOR_COMMAND_TO_COMPLETE = 5000;
- private Looper mLooper = null;
- private Handler mHandler = null;
-
- /**
- * Create and start a looper thread, return the Handler
- */
- public synchronized Handler start() throws Exception {
- final ConditionVariable startDone = new ConditionVariable();
- if (mLooper != null || mHandler !=null) {
- Log.w(TAG, "Looper thread already started");
- return mHandler;
- }
-
- new Thread() {
- @Override
- public void run() {
- if (VERBOSE) Log.v(TAG, "start loopRun");
- Looper.prepare();
- // Save the looper so that we can terminate this thread
- // after we are done with it.
- mLooper = Looper.myLooper();
- mHandler = new Handler();
- startDone.open();
- Looper.loop();
- if (VERBOSE) Log.v(TAG, "createLooperThread: finished");
- }
- }.start();
-
- if (VERBOSE) Log.v(TAG, "start waiting for looper");
- if (!startDone.block(WAIT_FOR_COMMAND_TO_COMPLETE)) {
- throw new TimeoutException("createLooperThread: start timeout");
- }
- return mHandler;
- }
-
- /**
- * Terminate the looper thread
- */
- public synchronized void close() throws Exception {
- if (mLooper == null || mHandler == null) {
- Log.w(TAG, "Looper thread doesn't start yet");
- return;
- }
-
- if (VERBOSE) Log.v(TAG, "Terminate looper thread");
- mLooper.quit();
- mLooper.getThread().join();
- mLooper = null;
- mHandler = null;
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- close();
- } finally {
- super.finalize();
- }
- }
-}
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
index 7f10cb8..779cb47 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -38,7 +38,11 @@
import java.io.IOException;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
/**
* A package private utility class for wrapping up the camera2 cts test common utility functions
@@ -47,11 +51,14 @@
private static final String TAG = "CameraTestUtils";
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+ // Only test the preview and video size that is no larger than 1080p.
+ public static final Size PREVIEW_SIZE_BOUND = new Size(1920, 1080);
// Default timeouts for reaching various states
- public static final int CAMERA_OPEN_TIMEOUT_MS = 500;
+ public static final int CAMERA_OPEN_TIMEOUT_MS = 2000;
+ public static final int CAMERA_CLOSE_TIMEOUT_MS = 2000;
public static final int CAMERA_IDLE_TIMEOUT_MS = 2000;
- public static final int CAMERA_ACTIVE_TIMEOUT_MS = 500;
- public static final int CAMERA_BUSY_TIMEOUT_MS = 500;
+ public static final int CAMERA_ACTIVE_TIMEOUT_MS = 1000;
+ public static final int CAMERA_BUSY_TIMEOUT_MS = 1000;
public static class ImageDropperListener implements ImageReader.OnImageAvailableListener {
@Override
@@ -287,7 +294,53 @@
String.format("Invalid format specified 0x%x", format));
}
Size[] availableSizes = properties.get(key);
+ assertArrayNotEmpty(availableSizes, "availableSizes should not be empty");
if (VERBOSE) Log.v(TAG, "Supported sizes are: " + Arrays.deepToString(availableSizes));
return availableSizes;
}
-}
\ No newline at end of file
+
+ /**
+ * Size comparator that compares the number of pixels it covers.
+ */
+ public static class SizeComparator implements Comparator<Size> {
+ @Override
+ public int compare(Size lhs, Size rhs) {
+ long left = lhs.getWidth() * lhs.getHeight();
+ long right = rhs.getWidth() * rhs.getHeight();
+ return (left < right) ? -1 : (left > right ? 1 : 0);
+ }
+ }
+
+ /**
+ * Get sorted size list in descending order. Remove the sizes larger than
+ * the bound. If the bound is null, don't do the size bound filtering.
+ */
+ static public List<Size> getSupportedPreviewSizes(
+ String cameraId, CameraManager cameraManager, Size bound) throws Exception {
+ Comparator<Size> comparator = new SizeComparator();
+ Size[] sizes = getSupportedSizeForFormat(ImageFormat.YUV_420_888, cameraId, cameraManager);
+ List<Size> supportedPreviewSizes = null;
+ if (bound != null) {
+ supportedPreviewSizes = new ArrayList<Size>(/* capacity */1);
+ for (Size sz : sizes) {
+ if (comparator.compare(sz, bound) <= 0) {
+ supportedPreviewSizes.add(sz);
+ }
+ }
+ } else {
+ supportedPreviewSizes = Arrays.asList(sizes);
+ }
+ assertTrue("Supported preview size should have at least one element",
+ supportedPreviewSizes.size() > 0);
+
+ Collections.sort(supportedPreviewSizes, comparator);
+ // Make it in descending order.
+ Collections.reverse(supportedPreviewSizes);
+ return supportedPreviewSizes;
+ }
+
+ static public List<Size> getSupportedVideoSizes(
+ String cameraId, CameraManager cameraManager, Size bound) throws Exception {
+ return getSupportedPreviewSizes(cameraId, cameraManager, bound);
+ }
+}
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
index 28cb13e..211b5d3 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
@@ -32,6 +32,7 @@
import android.media.ImageReader;
import android.os.Environment;
import android.os.Handler;
+import android.os.HandlerThread;
import android.test.AndroidTestCase;
import android.util.Log;
import android.view.Surface;
@@ -69,10 +70,10 @@
private CameraDevice mCamera;
private BlockingStateListener mCameraListener;
private String[] mCameraIds;
- private ImageReader mReader = null;
- private Handler mHandler = null;
- private SimpleImageListener mListener = null;
- private CameraTestThread mLooperThread = null;
+ private ImageReader mReader;
+ private Handler mHandler;
+ private SimpleImageListener mListener;
+ private HandlerThread mHandlerThread;
@Override
public void setContext(Context context) {
@@ -85,8 +86,9 @@
protected void setUp() throws Exception {
super.setUp();
mCameraIds = mCameraManager.getCameraIdList();
- mLooperThread = new CameraTestThread();
- mHandler = mLooperThread.start();
+ mHandlerThread = new HandlerThread(TAG);
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
mCameraListener = new BlockingStateListener();
}
@@ -100,7 +102,7 @@
mReader.close();
mReader = null;
}
- mLooperThread.close();
+ mHandlerThread.quitSafely();
mHandler = null;
super.tearDown();
}
@@ -110,7 +112,7 @@
Log.i(TAG, "Testing Camera " + mCameraIds[i]);
openDevice(mCameraIds[i]);
bufferFormatTestByCamera(ImageFormat.YUV_420_888, mCameraIds[i]);
- closeDevice(mCameraIds[i]);
+ closeDevice();
}
}
@@ -119,7 +121,7 @@
Log.v(TAG, "Testing Camera " + mCameraIds[i]);
openDevice(mCameraIds[i]);
bufferFormatTestByCamera(ImageFormat.JPEG, mCameraIds[i]);
- closeDevice(mCameraIds[i]);
+ closeDevice();
}
}
@@ -136,16 +138,8 @@
CameraCharacteristics properties = mCameraManager.getCameraCharacteristics(cameraId);
assertNotNull("Can't get camera properties!", properties);
- /**
- * TODO: cleanup the color format mess, we probably need define formats
- * in Image class instead of using ImageFormat for camera. also,
- * probably make sense to change the available format type from Enum[]
- * to int[]. It'll also be nice to put this into a helper function and
- * move to util class.
- */
int[] availableFormats = properties.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS);
- assertArrayNotEmpty(availableFormats,
- "availableFormats should not be empty");
+ assertArrayNotEmpty(availableFormats, "availableFormats should not be empty");
Arrays.sort(availableFormats);
assertTrue("Can't find the format " + format + " in supported formats " +
Arrays.toString(availableFormats),
@@ -160,7 +154,7 @@
prepareImageReader(sz, format);
- CaptureRequest request = prepareCaptureRequest(format);
+ CaptureRequest request = prepareCaptureRequest();
captureAndValidateImage(request, sz, format);
@@ -216,7 +210,7 @@
if (VERBOSE) Log.v(TAG, "Preparing ImageReader size " + sz.toString());
}
- private CaptureRequest prepareCaptureRequest(int format) throws Exception {
+ private CaptureRequest prepareCaptureRequest() throws Exception {
List<Surface> outputSurfaces = new ArrayList<Surface>(1);
Surface surface = mReader.getSurface();
assertNotNull("Fail to get surface from ImageReader", surface);
@@ -282,6 +276,7 @@
if (mCamera != null) {
throw new IllegalStateException("Already have open camera device");
}
+
try {
mCamera = CameraTestUtils.openCamera(
mCameraManager, cameraId, mCameraListener, mHandler);
@@ -292,11 +287,11 @@
mCamera = null;
fail("Fail to open camera, " + Log.getStackTraceString(e));
}
- mCameraListener.waitForState(STATE_UNCONFIGURED, CAMERA_OPEN_TIMEOUT_MS);
}
- private void closeDevice(String cameraId) {
+ private void closeDevice() {
mCamera.close();
+ mCameraListener.waitForState(STATE_CLOSED, CAMERA_CLOSE_TIMEOUT_MS);
mCamera = null;
}
@@ -335,7 +330,7 @@
BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length));
if (DUMP_FILE) {
String fileName =
- DEBUG_FILE_NAME_BASE + width + "x" + height + ".yuv";
+ DEBUG_FILE_NAME_BASE + "/" + width + "x" + height + ".jpeg";
dumpFile(fileName, jpegData);
}
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/CameraTest.java b/tests/tests/hardware/src/android/hardware/cts/CameraTest.java
index b198541..ec0977e 100644
--- a/tests/tests/hardware/src/android/hardware/cts/CameraTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/CameraTest.java
@@ -32,6 +32,7 @@
import android.media.CamcorderProfile;
import android.media.ExifInterface;
import android.media.MediaRecorder;
+import android.os.Build;
import android.os.ConditionVariable;
import android.os.Environment;
import android.os.Looper;
@@ -62,7 +63,7 @@
public class CameraTest extends ActivityInstrumentationTestCase2<CameraStubActivity> {
private static String TAG = "CameraTest";
private static final String PACKAGE = "com.android.cts.stub";
- private static final boolean LOGV = false;
+ private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
private final String JPEG_PATH = Environment.getExternalStorageDirectory().getPath() +
"/test.jpg";
private byte[] mJpegData;
@@ -90,6 +91,13 @@
private static final int AUTOEXPOSURE_LOCK = 0;
private static final int AUTOWHITEBALANCE_LOCK = 1;
+ // Some exif tags that are not defined by ExifInterface but supported.
+ private static final String TAG_DATETIME_DIGITIZED = "DateTimeDigitized";
+ private static final String TAG_SUBSEC_TIME = "SubSecTime";
+ private static final String TAG_SUBSEC_TIME_ORIG = "SubSecTimeOriginal";
+ private static final String TAG_SUBSEC_TIME_DIG = "SubSecTimeDigitized";
+
+
private PreviewCallback mPreviewCallback = new PreviewCallback();
private TestShutterCallback mShutterCallback = new TestShutterCallback();
private RawPictureCallback mRawPictureCallback = new RawPictureCallback();
@@ -107,7 +115,7 @@
public CameraTest() {
super(PACKAGE, CameraStubActivity.class);
- if (LOGV) Log.v(TAG, "Camera Constructor");
+ if (VERBOSE) Log.v(TAG, "Camera Constructor");
}
@Override
@@ -150,7 +158,7 @@
Log.v(TAG, "camera is opened");
startDone.open();
Looper.loop(); // Blocks forever until Looper.quit() is called.
- if (LOGV) Log.v(TAG, "initializeMessageLooper: quit.");
+ if (VERBOSE) Log.v(TAG, "initializeMessageLooper: quit.");
}
}.start();
@@ -186,7 +194,7 @@
private static int calculateBufferSize(int width, int height,
int format, int bpp) {
- if (LOGV) {
+ if (VERBOSE) {
Log.v(TAG, "calculateBufferSize: w=" + width + ",h=" + height
+ ",f=" + format + ",bpp=" + bpp);
}
@@ -203,7 +211,7 @@
int c_size = c_stride * height/2;
int size = y_size + c_size * 2;
- if (LOGV) {
+ if (VERBOSE) {
Log.v(TAG, "calculateBufferSize: YV12 size= " + size);
}
@@ -237,9 +245,9 @@
}
mPreviewCallbackResult = PREVIEW_CALLBACK_RECEIVED;
mCamera.stopPreview();
- if (LOGV) Log.v(TAG, "notify the preview callback");
+ if (VERBOSE) Log.v(TAG, "notify the preview callback");
mPreviewDone.open();
- if (LOGV) Log.v(TAG, "Preview callback stop");
+ if (VERBOSE) Log.v(TAG, "Preview callback stop");
}
}
@@ -247,7 +255,7 @@
private final class TestShutterCallback implements ShutterCallback {
public void onShutter() {
mShutterCallbackResult = true;
- if (LOGV) Log.v(TAG, "onShutter called");
+ if (VERBOSE) Log.v(TAG, "onShutter called");
}
}
@@ -255,7 +263,7 @@
private final class RawPictureCallback implements PictureCallback {
public void onPictureTaken(byte [] rawData, Camera camera) {
mRawPictureCallbackResult = true;
- if (LOGV) Log.v(TAG, "RawPictureCallback callback");
+ if (VERBOSE) Log.v(TAG, "RawPictureCallback callback");
}
}
@@ -272,14 +280,14 @@
outStream.close();
mJpegPictureCallbackResult = true;
- if (LOGV) {
+ if (VERBOSE) {
Log.v(TAG, "JpegPictureCallback rawDataLength = " + rawData.length);
}
} else {
mJpegPictureCallbackResult = false;
}
mSnapshotDone.open();
- if (LOGV) Log.v(TAG, "Jpeg Picture callback");
+ if (VERBOSE) Log.v(TAG, "Jpeg Picture callback");
} catch (IOException e) {
// no need to fail here; callback worked fine
Log.w(TAG, "Error writing picture to sd card.");
@@ -312,7 +320,7 @@
}
private void waitForPreviewDone() {
- if (LOGV) Log.v(TAG, "Wait for preview callback");
+ if (VERBOSE) Log.v(TAG, "Wait for preview callback");
if (!mPreviewDone.block(WAIT_FOR_COMMAND_TO_COMPLETE)) {
// timeout could be expected or unexpected. The caller will decide.
Log.v(TAG, "waitForPreviewDone: timeout");
@@ -339,7 +347,18 @@
}
private void checkPreviewCallback() throws Exception {
- if (LOGV) Log.v(TAG, "check preview callback");
+ if (VERBOSE) Log.v(TAG, "check preview callback");
+ mCamera.startPreview();
+ waitForPreviewDone();
+ mCamera.setPreviewCallback(null);
+ }
+
+ /**
+ * Start preview and wait for the first preview callback, which indicates the
+ * preview becomes active.
+ */
+ private void blockingStartPreview() {
+ mCamera.setPreviewCallback(new SimplePreviewStreamCb(/*Id*/0));
mCamera.startPreview();
waitForPreviewDone();
mCamera.setPreviewCallback(null);
@@ -384,7 +403,7 @@
assertEquals(pictureSize.height, bmpOptions.outHeight);
} else {
int realArea = bmpOptions.outWidth * bmpOptions.outHeight;
- if (LOGV) Log.v(TAG, "Video snapshot is " +
+ if (VERBOSE) Log.v(TAG, "Video snapshot is " +
bmpOptions.outWidth + " x " + bmpOptions.outHeight +
", video size is " + videoWidth + " x " + videoHeight);
assertTrue ("Video snapshot too small! Expected at least " +
@@ -809,6 +828,21 @@
assertTrue(mJpegPictureCallbackResult);
exif = new ExifInterface(JPEG_PATH);
assertFalse(exif.hasThumbnail());
+ // Primary image should still be valid for no thumbnail capture.
+ BitmapFactory.decodeFile(JPEG_PATH, bmpOptions);
+ if (!recording) {
+ assertTrue("Jpeg primary image size should match requested size",
+ bmpOptions.outWidth == pictureSize.width &&
+ bmpOptions.outHeight == pictureSize.height);
+ } else {
+ assertTrue(bmpOptions.outWidth >= recordingWidth ||
+ bmpOptions.outWidth == size.width);
+ assertTrue(bmpOptions.outHeight >= recordingHeight ||
+ bmpOptions.outHeight == size.height);
+ }
+
+ assertNotNull("Jpeg primary image data should be decodable",
+ BitmapFactory.decodeFile(JPEG_PATH));
}
@UiThreadTest
@@ -834,8 +868,10 @@
// Test various exif tags.
ExifInterface exif = new ExifInterface(JPEG_PATH);
- assertNotNull(exif.getAttribute(ExifInterface.TAG_MAKE));
- assertNotNull(exif.getAttribute(ExifInterface.TAG_MODEL));
+ StringBuffer failedCause = new StringBuffer("Jpeg exif test failed:\n");
+ boolean extraExiftestPassed = checkExtraExifTagsSucceeds(failedCause, exif);
+
+ if (VERBOSE) Log.v(TAG, "Testing exif tag TAG_DATETIME");
String datetime = exif.getAttribute(ExifInterface.TAG_DATETIME);
assertNotNull(datetime);
// Datetime should be local time.
@@ -848,6 +884,7 @@
assertBitmapAndJpegSizeEqual(mJpegData, exif);
// Test gps exif tags.
+ if (VERBOSE) Log.v(TAG, "Testing exif GPS tags");
testGpsExifValues(parameters, 37.736071, -122.441983, 21, 1199145600,
"GPS NETWORK HYBRID ARE ALL FINE.");
testGpsExifValues(parameters, 0.736071, 0.441983, 1, 1199145601, "GPS");
@@ -855,6 +892,7 @@
// Test gps tags do not exist after calling removeGpsData. Also check if
// image width and height exif match the jpeg when jpeg rotation is set.
+ if (VERBOSE) Log.v(TAG, "Testing exif GPS tag removal");
if (!recording) mCamera.startPreview();
parameters.removeGpsData();
parameters.setRotation(90); // For testing image width and height exif.
@@ -864,11 +902,164 @@
exif = new ExifInterface(JPEG_PATH);
checkGpsDataNull(exif);
assertBitmapAndJpegSizeEqual(mJpegData, exif);
+ assertTrue(failedCause.toString(), extraExiftestPassed);
// Reset the rotation to prevent from affecting other tests.
parameters.setRotation(0);
mCamera.setParameters(parameters);
}
+ /**
+ * Sanity check of some extra exif tags.
+ * <p>
+ * Sanity check some extra exif tags without asserting the check failures
+ * immediately. When a failure is detected, the failure cause is logged,
+ * the rest of the tests are still executed. The caller can assert with the
+ * failure cause based on the returned test status.
+ * </p>
+ *
+ * @param logBuf Log failure cause to this StringBuffer if there is
+ * any failure.
+ * @param exif The exif data associated with a jpeg image being tested.
+ * @return true if no test failure is found, false if there is any failure.
+ */
+ private boolean checkExtraExifTagsSucceeds(StringBuffer logBuf, ExifInterface exif) {
+ if (logBuf == null || exif == null) {
+ throw new IllegalArgumentException("failureCause and exif shouldn't be null");
+ }
+
+ if (VERBOSE) Log.v(TAG, "Testing extra exif tags");
+ boolean allTestsPassed = true;
+ boolean passedSoFar = true;
+ String failureMsg;
+
+ // TAG_EXPOSURE_TIME
+ // ExifInterface API gives exposure time value in the form of float instead of rational
+ String exposureTime = exif.getAttribute(ExifInterface.TAG_EXPOSURE_TIME);
+ passedSoFar = expectNotNull("Exif TAG_EXPOSURE_TIME is null!", logBuf, exposureTime);
+ if (passedSoFar) {
+ double exposureTimeValue = Double.parseDouble(exposureTime);
+ failureMsg = "Exif exposure time " + exposureTime + " should be a positive value";
+ passedSoFar = expectTrue(failureMsg, logBuf, exposureTimeValue > 0);
+ }
+ allTestsPassed = allTestsPassed && passedSoFar;
+
+ // TAG_APERTURE
+ // ExifInterface API gives aperture value in the form of float instead of rational
+ String aperture = exif.getAttribute(ExifInterface.TAG_APERTURE);
+ passedSoFar = expectNotNull("Exif TAG_APERTURE is null!", logBuf, aperture);
+ if (passedSoFar) {
+ double apertureValue = Double.parseDouble(aperture);
+ passedSoFar = expectTrue("Exif TAG_APERTURE value " + aperture + " should be positive!",
+ logBuf, apertureValue > 0);
+ }
+ allTestsPassed = allTestsPassed && passedSoFar;
+
+ // TAG_FLASH
+ String flash = exif.getAttribute(ExifInterface.TAG_FLASH);
+ passedSoFar = expectNotNull("Exif TAG_FLASH is null!", logBuf, flash);
+ allTestsPassed = allTestsPassed && passedSoFar;
+
+ // TAG_WHITE_BALANCE
+ String whiteBalance = exif.getAttribute(ExifInterface.TAG_WHITE_BALANCE);
+ passedSoFar = expectNotNull("Exif TAG_WHITE_BALANCE is null!", logBuf, whiteBalance);
+ allTestsPassed = allTestsPassed && passedSoFar;
+
+ // TAG_MAKE
+ String make = exif.getAttribute(ExifInterface.TAG_MAKE);
+ passedSoFar = expectNotNull("Exif TAG_MAKE is null!", logBuf, make);
+ if (passedSoFar) {
+ passedSoFar = expectTrue("Exif TAG_MODEL value: " + make
+ + " should match build manufacturer: " + Build.MANUFACTURER, logBuf,
+ make.equals(Build.MANUFACTURER));
+ }
+ allTestsPassed = allTestsPassed && passedSoFar;
+
+ // TAG_MODEL
+ String model = exif.getAttribute(ExifInterface.TAG_MODEL);
+ passedSoFar = expectNotNull("Exif TAG_MODEL is null!", logBuf, model);
+ if (passedSoFar) {
+ passedSoFar = expectTrue("Exif TAG_MODEL value: " + model
+ + " should match build manufacturer: " + Build.MODEL, logBuf,
+ model.equals(Build.MODEL));
+ }
+ allTestsPassed = allTestsPassed && passedSoFar;
+
+ // TAG_ISO
+ int iso = exif.getAttributeInt(ExifInterface.TAG_ISO, -1);
+ passedSoFar = expectTrue("Exif ISO value " + iso + " is invalid", logBuf, iso > 0);
+ allTestsPassed = allTestsPassed && passedSoFar;
+
+ // TAG_DATETIME_DIGITIZED (a.k.a Create time for digital cameras).
+ String digitizedTime = exif.getAttribute(TAG_DATETIME_DIGITIZED);
+ passedSoFar = expectNotNull("Exif TAG_DATETIME_DIGITIZED is null!", logBuf, digitizedTime);
+ if (passedSoFar) {
+ String datetime = exif.getAttribute(ExifInterface.TAG_DATETIME);
+ passedSoFar = expectNotNull("Exif TAG_DATETIME is null!", logBuf, datetime);
+ if (passedSoFar) {
+ passedSoFar = expectTrue("dataTime should match digitizedTime", logBuf,
+ digitizedTime.equals(datetime));
+ }
+ }
+ allTestsPassed = allTestsPassed && passedSoFar;
+
+ /**
+ * TAG_SUBSEC_TIME. Since the sub second tag strings are truncated to at
+ * most 9 digits in ExifInterface implementation, use getAttributeInt to
+ * sanitize it. When the default value -1 is returned, it means that
+ * this exif tag either doesn't exist or is a non-numerical invalid
+ * string. Same rule applies to the rest of sub second tags.
+ */
+ int subSecTime = exif.getAttributeInt(TAG_SUBSEC_TIME, -1);
+ passedSoFar = expectTrue(
+ "Exif TAG_SUBSEC_TIME value is null or invalid!", logBuf, subSecTime > 0);
+ allTestsPassed = allTestsPassed && passedSoFar;
+
+ // TAG_SUBSEC_TIME_ORIG
+ int subSecTimeOrig = exif.getAttributeInt(TAG_SUBSEC_TIME_ORIG, -1);
+ passedSoFar = expectTrue(
+ "Exif TAG_SUBSEC_TIME_ORIG value is null or invalid!", logBuf, subSecTimeOrig > 0);
+ allTestsPassed = allTestsPassed && passedSoFar;
+
+ // TAG_SUBSEC_TIME_DIG
+ int subSecTimeDig = exif.getAttributeInt(TAG_SUBSEC_TIME_DIG, -1);
+ passedSoFar = expectTrue(
+ "Exif TAG_SUBSEC_TIME_DIG value is null or invalid!", logBuf, subSecTimeDig > 0);
+ allTestsPassed = allTestsPassed && passedSoFar;
+
+ return allTestsPassed;
+ }
+
+ /**
+ * Check if object is null and log failure msg.
+ *
+ * @param msg Failure msg.
+ * @param logBuffer StringBuffer to log the failure msg.
+ * @param obj Object to test.
+ * @return true if object is not null, otherwise return false.
+ */
+ private boolean expectNotNull(String msg, StringBuffer logBuffer, Object obj)
+ {
+ if (obj == null) {
+ logBuffer.append(msg + "\n");
+ }
+ return (obj != null);
+ }
+
+ /**
+ * Check if condition is false and log failure msg.
+ *
+ * @param msg Failure msg.
+ * @param logBuffer StringBuffer to log the failure msg.
+ * @param condition Condition to test.
+ * @return The value of the condition.
+ */
+ private boolean expectTrue(String msg, StringBuffer logBuffer, boolean condition) {
+ if (!condition) {
+ logBuffer.append(msg + "\n");
+ }
+ return condition;
+ }
+
private void assertBitmapAndJpegSizeEqual(byte[] jpegData, ExifInterface exif) {
int exifWidth = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0);
int exifHeight = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0);
@@ -1152,8 +1343,7 @@
for (int i = 0; i < ratios.size() - 1; i++) {
assertTrue(ratios.get(i) < ratios.get(i + 1));
}
- mCamera.startPreview();
- waitForPreviewDone();
+ blockingStartPreview();
// Test each zoom step.
for (int i = 0; i <= maxZoom; i++) {
@@ -1316,8 +1506,8 @@
private void testFocusDistancesByCamera(int cameraId) throws Exception {
initializeMessageLooper(cameraId);
- mCamera.startPreview();
- waitForPreviewDone();
+ blockingStartPreview();
+
Parameters parameters = mCamera.getParameters();
// Test every supported focus mode.
@@ -1785,7 +1975,7 @@
double intervalMargin = 0.9;
long lastArrivalTime = mFrames.get(mFrames.size() - 1);
double interval = arrivalTime - lastArrivalTime;
- if (LOGV) Log.v(TAG, "Frame interval=" + interval);
+ if (VERBOSE) Log.v(TAG, "Frame interval=" + interval);
try {
assertTrue("Frame interval (" + interval + "ms) is too " +
"large. mMaxFrameInterval=" +
@@ -1890,8 +2080,7 @@
// Make sure scene mode settings are consistent before preview and
// after preview.
- mCamera.startPreview();
- waitForPreviewDone();
+ blockingStartPreview();
for (int i = 0; i < supportedSceneModes.size(); i++) {
String sceneMode = supportedSceneModes.get(i);
parameters.setSceneMode(sceneMode);
@@ -2064,7 +2253,7 @@
@UiThreadTest
public void testMultiCameraRelease() throws Exception {
// Verify that multiple cameras exist, and that they can be opened at the same time
- if (LOGV) Log.v(TAG, "testMultiCameraRelease: Checking pre-conditions.");
+ if (VERBOSE) Log.v(TAG, "testMultiCameraRelease: Checking pre-conditions.");
int nCameras = Camera.getNumberOfCameras();
if (nCameras < 2) {
Log.i(TAG, "Test multi-camera release: Skipping test because only 1 camera available");
@@ -2086,11 +2275,11 @@
testCamera1.release();
// Start first camera
- if (LOGV) Log.v(TAG, "testMultiCameraRelease: Opening camera 0");
+ if (VERBOSE) Log.v(TAG, "testMultiCameraRelease: Opening camera 0");
initializeMessageLooper(0);
SimplePreviewStreamCb callback0 = new SimplePreviewStreamCb(0);
mCamera.setPreviewCallback(callback0);
- if (LOGV) Log.v(TAG, "testMultiCameraRelease: Starting preview on camera 0");
+ if (VERBOSE) Log.v(TAG, "testMultiCameraRelease: Starting preview on camera 0");
mCamera.startPreview();
// Run preview for a bit
for (int f = 0; f < 100; f++) {
@@ -2098,7 +2287,7 @@
assertTrue("testMultiCameraRelease: First camera preview timed out on frame " + f + "!",
mPreviewDone.block( WAIT_FOR_COMMAND_TO_COMPLETE));
}
- if (LOGV) Log.v(TAG, "testMultiCameraRelease: Stopping preview on camera 0");
+ if (VERBOSE) Log.v(TAG, "testMultiCameraRelease: Stopping preview on camera 0");
mCamera.stopPreview();
// Save message looper and camera to deterministically release them, instead
// of letting GC do it at some point.
@@ -2110,11 +2299,11 @@
// Start second camera without releasing the first one (will
// set mCamera and mLooper to new objects)
- if (LOGV) Log.v(TAG, "testMultiCameraRelease: Opening camera 1");
+ if (VERBOSE) Log.v(TAG, "testMultiCameraRelease: Opening camera 1");
initializeMessageLooper(1);
SimplePreviewStreamCb callback1 = new SimplePreviewStreamCb(1);
mCamera.setPreviewCallback(callback1);
- if (LOGV) Log.v(TAG, "testMultiCameraRelease: Starting preview on camera 1");
+ if (VERBOSE) Log.v(TAG, "testMultiCameraRelease: Starting preview on camera 1");
mCamera.startPreview();
// Run preview for a bit - GC of first camera instance should not impact the second's
// operation.
@@ -2124,11 +2313,11 @@
mPreviewDone.block( WAIT_FOR_COMMAND_TO_COMPLETE));
if (f == 50) {
// Release first camera mid-preview, should cause no problems
- if (LOGV) Log.v(TAG, "testMultiCameraRelease: Releasing camera 0");
+ if (VERBOSE) Log.v(TAG, "testMultiCameraRelease: Releasing camera 0");
firstCamera.release();
}
}
- if (LOGV) Log.v(TAG, "testMultiCameraRelease: Stopping preview on camera 0");
+ if (VERBOSE) Log.v(TAG, "testMultiCameraRelease: Stopping preview on camera 0");
mCamera.stopPreview();
firstLooper.quit();
@@ -2144,7 +2333,7 @@
mId = id;
}
public void onPreviewFrame(byte[] data, android.hardware.Camera camera) {
- if (LOGV) Log.v(TAG, "Preview frame callback, id " + mId + ".");
+ if (VERBOSE) Log.v(TAG, "Preview frame callback, id " + mId + ".");
mPreviewDone.open();
}
}
diff --git a/tests/tests/media/res/raw/big5_1.mp3 b/tests/tests/media/res/raw/big5_1.mp3
new file mode 100644
index 0000000..faa3eb4
--- /dev/null
+++ b/tests/tests/media/res/raw/big5_1.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/big5_2.mp3 b/tests/tests/media/res/raw/big5_2.mp3
new file mode 100644
index 0000000..a69da4f
--- /dev/null
+++ b/tests/tests/media/res/raw/big5_2.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/cp1251_3.mp3 b/tests/tests/media/res/raw/cp1251_3.mp3
new file mode 100644
index 0000000..179a1a5
--- /dev/null
+++ b/tests/tests/media/res/raw/cp1251_3.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/cp1251_4.mp3 b/tests/tests/media/res/raw/cp1251_4.mp3
new file mode 100644
index 0000000..3df1d32
--- /dev/null
+++ b/tests/tests/media/res/raw/cp1251_4.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/cp1251_5.mp3 b/tests/tests/media/res/raw/cp1251_5.mp3
new file mode 100644
index 0000000..46df442
--- /dev/null
+++ b/tests/tests/media/res/raw/cp1251_5.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/cp1251_6.mp3 b/tests/tests/media/res/raw/cp1251_6.mp3
new file mode 100644
index 0000000..545834d
--- /dev/null
+++ b/tests/tests/media/res/raw/cp1251_6.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/cp1251_v1.mp3 b/tests/tests/media/res/raw/cp1251_v1.mp3
new file mode 100644
index 0000000..173d970
--- /dev/null
+++ b/tests/tests/media/res/raw/cp1251_v1.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/cp1251_v1v2.mp3 b/tests/tests/media/res/raw/cp1251_v1v2.mp3
new file mode 100644
index 0000000..abffa92
--- /dev/null
+++ b/tests/tests/media/res/raw/cp1251_v1v2.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/gb18030_1.mp3 b/tests/tests/media/res/raw/gb18030_1.mp3
new file mode 100644
index 0000000..dc63de5
--- /dev/null
+++ b/tests/tests/media/res/raw/gb18030_1.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/gb18030_2.mp3 b/tests/tests/media/res/raw/gb18030_2.mp3
new file mode 100644
index 0000000..6109c97
--- /dev/null
+++ b/tests/tests/media/res/raw/gb18030_2.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/gb18030_3.mp3 b/tests/tests/media/res/raw/gb18030_3.mp3
new file mode 100644
index 0000000..4fcb22f
--- /dev/null
+++ b/tests/tests/media/res/raw/gb18030_3.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/gb18030_4.mp3 b/tests/tests/media/res/raw/gb18030_4.mp3
new file mode 100644
index 0000000..fedffd7
--- /dev/null
+++ b/tests/tests/media/res/raw/gb18030_4.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/gb18030_5.mp3 b/tests/tests/media/res/raw/gb18030_5.mp3
new file mode 100644
index 0000000..70f76ce
--- /dev/null
+++ b/tests/tests/media/res/raw/gb18030_5.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/gb18030_6.mp3 b/tests/tests/media/res/raw/gb18030_6.mp3
new file mode 100644
index 0000000..b4817b2
--- /dev/null
+++ b/tests/tests/media/res/raw/gb18030_6.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/gb18030_7.mp3 b/tests/tests/media/res/raw/gb18030_7.mp3
new file mode 100644
index 0000000..7932596
--- /dev/null
+++ b/tests/tests/media/res/raw/gb18030_7.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/gb18030_8.mp3 b/tests/tests/media/res/raw/gb18030_8.mp3
new file mode 100644
index 0000000..f5f54de
--- /dev/null
+++ b/tests/tests/media/res/raw/gb18030_8.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/hebrew.mp3 b/tests/tests/media/res/raw/hebrew.mp3
new file mode 100644
index 0000000..59d76d8
--- /dev/null
+++ b/tests/tests/media/res/raw/hebrew.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/hebrew2.mp3 b/tests/tests/media/res/raw/hebrew2.mp3
new file mode 100644
index 0000000..d48cad2
--- /dev/null
+++ b/tests/tests/media/res/raw/hebrew2.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/iso88591_1.ogg b/tests/tests/media/res/raw/iso88591_1.ogg
new file mode 100644
index 0000000..c20bf34
--- /dev/null
+++ b/tests/tests/media/res/raw/iso88591_1.ogg
Binary files differ
diff --git a/tests/tests/media/res/raw/shiftjis1.mp3 b/tests/tests/media/res/raw/shiftjis1.mp3
new file mode 100644
index 0000000..1c50c76
--- /dev/null
+++ b/tests/tests/media/res/raw/shiftjis1.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/shiftjis2.mp3 b/tests/tests/media/res/raw/shiftjis2.mp3
new file mode 100644
index 0000000..808c597
--- /dev/null
+++ b/tests/tests/media/res/raw/shiftjis2.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/shiftjis3.mp3 b/tests/tests/media/res/raw/shiftjis3.mp3
new file mode 100644
index 0000000..820631b
--- /dev/null
+++ b/tests/tests/media/res/raw/shiftjis3.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/shiftjis4.mp3 b/tests/tests/media/res/raw/shiftjis4.mp3
new file mode 100644
index 0000000..3fbc25e
--- /dev/null
+++ b/tests/tests/media/res/raw/shiftjis4.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/shiftjis5.mp3 b/tests/tests/media/res/raw/shiftjis5.mp3
new file mode 100644
index 0000000..90520f8
--- /dev/null
+++ b/tests/tests/media/res/raw/shiftjis5.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/shiftjis6.mp3 b/tests/tests/media/res/raw/shiftjis6.mp3
new file mode 100644
index 0000000..5310936
--- /dev/null
+++ b/tests/tests/media/res/raw/shiftjis6.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/shiftjis7.mp3 b/tests/tests/media/res/raw/shiftjis7.mp3
new file mode 100644
index 0000000..6143126
--- /dev/null
+++ b/tests/tests/media/res/raw/shiftjis7.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/shiftjis8.mp3 b/tests/tests/media/res/raw/shiftjis8.mp3
new file mode 100644
index 0000000..c45c130
--- /dev/null
+++ b/tests/tests/media/res/raw/shiftjis8.mp3
Binary files differ
diff --git a/tests/tests/media/src/android/media/cts/DecoderTest.java b/tests/tests/media/src/android/media/cts/DecoderTest.java
index f250c3d..eda4546 100644
--- a/tests/tests/media/src/android/media/cts/DecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTest.java
@@ -33,6 +33,7 @@
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.zip.CRC32;
public class DecoderTest extends MediaPlayerTestBase {
@@ -42,6 +43,11 @@
private static final int RESET_MODE_RECONFIGURE = 1;
private static final int RESET_MODE_FLUSH = 2;
+ private static final String[] CSD_KEYS = new String[] { "csd-0", "csd-1" };
+
+ private static final int CONFIG_MODE_NONE = 0;
+ private static final int CONFIG_MODE_QUEUE = 1;
+
private Resources mResources;
short[] mMasterBuffer;
@@ -69,6 +75,20 @@
masterFd.close();
}
+ // TODO: add similar tests for other audio and video formats
+ public void testBug11696552() throws Exception {
+ MediaCodec mMediaCodec = MediaCodec.createDecoderByType("audio/mp4a-latm");
+ MediaFormat mFormat = MediaFormat.createAudioFormat("audio/mp4a-latm", 48000, 2);
+ mFormat.setByteBuffer("csd-0", ByteBuffer.wrap( new byte [] {0x13, 0x10} ));
+ mFormat.setInteger(MediaFormat.KEY_IS_ADTS, 1);
+ mMediaCodec.configure(mFormat, null, null, 0);
+ mMediaCodec.start();
+ int index = mMediaCodec.dequeueInputBuffer(250000);
+ mMediaCodec.queueInputBuffer(index, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM );
+ MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+ mMediaCodec.dequeueOutputBuffer(info, 250000);
+ }
+
// The allowed errors in the following tests are the actual maximum measured
// errors with the standard decoders, plus 10%.
// This should allow for some variation in decoders, while still detecting
@@ -105,7 +125,7 @@
}
private void monoTest(int res) throws Exception {
- short [] mono = decodeToMemory(res, RESET_MODE_NONE);
+ short [] mono = decodeToMemory(res, RESET_MODE_NONE, CONFIG_MODE_NONE, -1, null);
if (mono.length == 44100) {
// expected
} else if (mono.length == 88200) {
@@ -118,14 +138,11 @@
fail("wrong number of samples: " + mono.length);
}
- // we should get the same data when reconfiguring the codec
- short [] mono2 = decodeToMemory(res, RESET_MODE_RECONFIGURE);
+ short [] mono2 = decodeToMemory(res, RESET_MODE_RECONFIGURE, CONFIG_MODE_NONE, -1, null);
assertTrue(Arrays.equals(mono, mono2));
- // NOTE: coming soon
- // and when flushing it
-// short [] mono3 = decodeToMemory(res, RESET_MODE_FLUSH);
-// assertTrue(Arrays.equals(mono, mono3));
+ short [] mono3 = decodeToMemory(res, RESET_MODE_FLUSH, CONFIG_MODE_NONE, -1, null);
+ assertTrue(Arrays.equals(mono, mono3));
}
/**
@@ -135,7 +152,7 @@
*/
private void decode(int testinput, float maxerror) throws IOException {
- short [] decoded = decodeToMemory(testinput, RESET_MODE_NONE);
+ short[] decoded = decodeToMemory(testinput, RESET_MODE_NONE, CONFIG_MODE_NONE, -1, null);
assertEquals("wrong data size", mMasterBuffer.length, decoded.length);
@@ -152,22 +169,53 @@
double rmse = Math.sqrt(avgErrorSquared);
assertTrue("decoding error too big: " + rmse, rmse <= maxerror);
- short [] decoded2 = decodeToMemory(testinput, RESET_MODE_RECONFIGURE);
- assertEquals("count different with reconfigure", decoded.length, decoded2.length);
- for (int i = 0; i < decoded.length; i++) {
- assertEquals("samples don't match", decoded[i], decoded2[i]);
- }
+ int[] resetModes = new int[] { RESET_MODE_NONE, RESET_MODE_RECONFIGURE, RESET_MODE_FLUSH };
+ int[] configModes = new int[] { CONFIG_MODE_NONE, CONFIG_MODE_QUEUE };
- // NOTE: coming soon
-// short [] decoded3 = decodeToMemory(testinput, RESET_MODE_FLUSH);
-// assertEquals("count different with flush", decoded.length, decoded3.length);
-// for (int i = 0; i < decoded.length; i++) {
-// assertEquals("samples don't match", decoded[i], decoded3[i]);
-// }
+ for (int conf : configModes) {
+ for (int reset : resetModes) {
+ if (conf == CONFIG_MODE_NONE && reset == RESET_MODE_NONE) {
+ // default case done outside of loop
+ continue;
+ }
+ if (conf == CONFIG_MODE_QUEUE && !hasAudioCsd(testinput)) {
+ continue;
+ }
+
+ String params = String.format("(using reset: %d, config: %s)", reset, conf);
+ short[] decoded2 = decodeToMemory(testinput, reset, conf, -1, null);
+ assertEquals("count different with reconfigure" + params,
+ decoded.length, decoded2.length);
+ for (int i = 0; i < decoded.length; i++) {
+ assertEquals("samples don't match" + params, decoded[i], decoded2[i]);
+ }
+ }
+ }
}
- private short[] decodeToMemory(int testinput, int resetMode) throws IOException {
+ private boolean hasAudioCsd(int testinput) throws IOException {
+ AssetFileDescriptor fd = null;
+ try {
+ fd = mResources.openRawResourceFd(testinput);
+ MediaExtractor extractor = new MediaExtractor();
+ extractor.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
+ MediaFormat format = extractor.getTrackFormat(0);
+
+ return format.containsKey(CSD_KEYS[0]);
+
+ } finally {
+ if (fd != null) {
+ fd.close();
+ }
+ }
+ }
+
+ private short[] decodeToMemory(int testinput, int resetMode, int configMode,
+ int eossample, List<Long> timestamps) throws IOException {
+
+ String localTag = TAG + "#decodeToMemory";
+ Log.v(localTag, String.format("reset = %d; config: %s", resetMode, configMode));
short [] decoded = new short[0];
int decodedIdx = 0;
@@ -188,15 +236,32 @@
String mime = format.getString(MediaFormat.KEY_MIME);
assertTrue("not an audio file", mime.startsWith("audio/"));
+ MediaFormat configFormat = format;
codec = MediaCodec.createDecoderByType(mime);
- codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
+ if (configMode == CONFIG_MODE_QUEUE && format.containsKey(CSD_KEYS[0])) {
+ configFormat = MediaFormat.createAudioFormat(mime,
+ format.getInteger(MediaFormat.KEY_SAMPLE_RATE),
+ format.getInteger(MediaFormat.KEY_CHANNEL_COUNT));
+
+ configFormat.setLong(MediaFormat.KEY_DURATION,
+ format.getLong(MediaFormat.KEY_DURATION));
+ String[] keys = new String[] { "max-input-size", "encoder-delay", "encoder-padding" };
+ for (String k : keys) {
+ if (format.containsKey(k)) {
+ configFormat.setInteger(k, format.getInteger(k));
+ }
+ }
+ }
+ Log.v(localTag, "configuring with " + configFormat);
+ codec.configure(configFormat, null /* surface */, null /* crypto */, 0 /* flags */);
+
codec.start();
codecInputBuffers = codec.getInputBuffers();
codecOutputBuffers = codec.getOutputBuffers();
if (resetMode == RESET_MODE_RECONFIGURE) {
codec.stop();
- codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
+ codec.configure(configFormat, null /* surface */, null /* crypto */, 0 /* flags */);
codec.start();
codecInputBuffers = codec.getInputBuffers();
codecOutputBuffers = codec.getOutputBuffers();
@@ -206,12 +271,17 @@
extractor.selectTrack(0);
+ if (configMode == CONFIG_MODE_QUEUE) {
+ queueConfig(codec, format);
+ }
+
// start decoding
final long kTimeOutUs = 5000;
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
boolean sawInputEOS = false;
boolean sawOutputEOS = false;
int noOutputCounter = 0;
+ int samplecounter = 0;
while (!sawOutputEOS && noOutputCounter < 50) {
noOutputCounter++;
if (!sawInputEOS) {
@@ -225,14 +295,20 @@
long presentationTimeUs = 0;
+ if (sampleSize < 0 && eossample > 0) {
+ fail("test is broken: never reached eos sample");
+ }
if (sampleSize < 0) {
Log.d(TAG, "saw input EOS.");
sawInputEOS = true;
sampleSize = 0;
} else {
+ if (samplecounter == eossample) {
+ sawInputEOS = true;
+ }
+ samplecounter++;
presentationTimeUs = extractor.getSampleTime();
}
-
codec.queueInputBuffer(
inputBufIndex,
0 /* offset */,
@@ -253,22 +329,32 @@
if (info.size > 0) {
noOutputCounter = 0;
+ if (timestamps != null) {
+ timestamps.add(info.presentationTimeUs);
+ }
}
if (info.size > 0 && resetMode != RESET_MODE_NONE) {
// once we've gotten some data out of the decoder, reset and start again
if (resetMode == RESET_MODE_RECONFIGURE) {
codec.stop();
- codec.configure(format, null /* surface */, null /* crypto */,
+ codec.configure(configFormat, null /* surface */, null /* crypto */,
0 /* flags */);
codec.start();
codecInputBuffers = codec.getInputBuffers();
codecOutputBuffers = codec.getOutputBuffers();
+ if (configMode == CONFIG_MODE_QUEUE) {
+ queueConfig(codec, format);
+ }
} else /* resetMode == RESET_MODE_FLUSH */ {
codec.flush();
}
resetMode = RESET_MODE_NONE;
extractor.seekTo(0, MediaExtractor.SEEK_TO_NEXT_SYNC);
sawInputEOS = false;
+ samplecounter = 0;
+ if (timestamps != null) {
+ timestamps.clear();
+ }
continue;
}
@@ -279,8 +365,9 @@
decoded = Arrays.copyOf(decoded, decodedIdx + (info.size / 2));
}
+ buf.position(info.offset);
for (int i = 0; i < info.size; i += 2) {
- decoded[decodedIdx++] = buf.getShort(i);
+ decoded[decodedIdx++] = buf.getShort();
}
codec.releaseOutputBuffer(outputBufIndex, false /* render */);
@@ -301,12 +388,106 @@
Log.d(TAG, "dequeueOutputBuffer returned " + res);
}
}
+ if (noOutputCounter >= 50) {
+ fail("decoder stopped outputing data");
+ }
codec.stop();
codec.release();
return decoded;
}
+ private void queueConfig(MediaCodec codec, MediaFormat format) {
+ for (String csdKey : CSD_KEYS) {
+ if (!format.containsKey(csdKey)) {
+ continue;
+ }
+ ByteBuffer[] codecInputBuffers = codec.getInputBuffers();
+ int inputBufIndex = codec.dequeueInputBuffer(-1);
+ if (inputBufIndex < 0) {
+ fail("failed to queue configuration buffer " + csdKey);
+ } else {
+ ByteBuffer csd = (ByteBuffer) format.getByteBuffer(csdKey).rewind();
+ Log.v(TAG + "#queueConfig", String.format("queueing %s:%s", csdKey, csd));
+ codecInputBuffers[inputBufIndex].put(csd);
+ codec.queueInputBuffer(
+ inputBufIndex,
+ 0 /* offset */,
+ csd.limit(),
+ 0 /* presentation time (us) */,
+ MediaCodec.BUFFER_FLAG_CODEC_CONFIG);
+ }
+ }
+ }
+
+ public void testDecodeWithEOSOnLastBuffer() throws Exception {
+ testDecodeWithEOSOnLastBuffer(R.raw.sinesweepm4a);
+ testDecodeWithEOSOnLastBuffer(R.raw.sinesweepmp3lame);
+ testDecodeWithEOSOnLastBuffer(R.raw.sinesweepmp3smpb);
+ testDecodeWithEOSOnLastBuffer(R.raw.sinesweepwav);
+ testDecodeWithEOSOnLastBuffer(R.raw.sinesweepflac);
+ testDecodeWithEOSOnLastBuffer(R.raw.sinesweepogg);
+ }
+
+ /* setting EOS on the last full input buffer should be equivalent to setting EOS on an empty
+ * input buffer after all the full ones. */
+ private void testDecodeWithEOSOnLastBuffer(int res) throws Exception {
+ int numsamples = countSamples(res);
+ assertTrue(numsamples != 0);
+
+ List<Long> timestamps1 = new ArrayList<Long>();
+ short[] decode1 = decodeToMemory(res, RESET_MODE_NONE, CONFIG_MODE_NONE, -1, timestamps1);
+
+ List<Long> timestamps2 = new ArrayList<Long>();
+ short[] decode2 = decodeToMemory(res, RESET_MODE_NONE, CONFIG_MODE_NONE, numsamples - 1,
+ timestamps2);
+
+ // check that the data and the timestamps are the same for EOS-on-last and EOS-after-last
+ assertEquals(decode1.length, decode2.length);
+ assertTrue(Arrays.equals(decode1, decode2));
+ assertEquals(timestamps1.size(), timestamps2.size());
+ assertTrue(timestamps1.equals(timestamps2));
+
+ // ... and that this is also true when reconfiguring the codec
+ timestamps2.clear();
+ decode2 = decodeToMemory(res, RESET_MODE_RECONFIGURE, CONFIG_MODE_NONE, -1, timestamps2);
+ assertTrue(Arrays.equals(decode1, decode2));
+ assertTrue(timestamps1.equals(timestamps2));
+ timestamps2.clear();
+ decode2 = decodeToMemory(res, RESET_MODE_RECONFIGURE, CONFIG_MODE_NONE, numsamples - 1,
+ timestamps2);
+ assertEquals(decode1.length, decode2.length);
+ assertTrue(Arrays.equals(decode1, decode2));
+ assertTrue(timestamps1.equals(timestamps2));
+
+ // ... and that this is also true when flushing the codec
+ timestamps2.clear();
+ decode2 = decodeToMemory(res, RESET_MODE_FLUSH, CONFIG_MODE_NONE, -1, timestamps2);
+ assertTrue(Arrays.equals(decode1, decode2));
+ assertTrue(timestamps1.equals(timestamps2));
+ timestamps2.clear();
+ decode2 = decodeToMemory(res, RESET_MODE_FLUSH, CONFIG_MODE_NONE, numsamples - 1,
+ timestamps2);
+ assertEquals(decode1.length, decode2.length);
+ assertTrue(Arrays.equals(decode1, decode2));
+ assertTrue(timestamps1.equals(timestamps2));
+ }
+
+ private int countSamples(int res) throws IOException {
+ AssetFileDescriptor testFd = mResources.openRawResourceFd(res);
+
+ MediaExtractor extractor = new MediaExtractor();
+ extractor.setDataSource(testFd.getFileDescriptor(), testFd.getStartOffset(),
+ testFd.getLength());
+ testFd.close();
+ extractor.selectTrack(0);
+ int numsamples = 0;
+ while (extractor.advance()) {
+ numsamples++;
+ }
+ return numsamples;
+ }
+
public void testCodecBasicH264() throws Exception {
Surface s = getActivity().getSurfaceHolder().getSurface();
int frames1 = countFrames(
@@ -472,21 +653,21 @@
// }
public void testCodecResetsMp3() throws Exception {
- testCodecReconfig(R.raw.sinesweepmp3lame, null);
+ testCodecReconfig(R.raw.sinesweepmp3lame);
// NOTE: replacing testCodecReconfig call soon
// testCodecResets(R.raw.sinesweepmp3lame, null);
}
public void testCodecResetsM4a() throws Exception {
- testCodecReconfig(R.raw.sinesweepm4a, null);
+ testCodecReconfig(R.raw.sinesweepm4a);
// NOTE: replacing testCodecReconfig call soon
// testCodecResets(R.raw.sinesweepm4a, null);
}
- private void testCodecReconfig(int video, Surface s) throws Exception {
- int frames1 = countFrames(video, RESET_MODE_NONE, -1 /* eosframe */, s);
- int frames2 = countFrames(video, RESET_MODE_RECONFIGURE, -1 /* eosframe */, s);
- assertEquals("different number of frames when using reconfigured codec", frames1, frames2);
+ private void testCodecReconfig(int audio) throws Exception {
+ int size1 = countSize(audio, RESET_MODE_NONE, -1 /* eosframe */);
+ int size2 = countSize(audio, RESET_MODE_RECONFIGURE, -1 /* eosframe */);
+ assertEquals("different output size when using reconfigured codec", size1, size2);
}
private void testCodecResets(int video, Surface s) throws Exception {
@@ -497,7 +678,7 @@
assertEquals("different number of frames when using flushed codec", frames1, frames3);
}
- private MediaCodec createDecoder(String mime) {
+ private static MediaCodec createDecoder(String mime) {
if (false) {
// change to force testing software codecs
if (mime.contains("avc")) {
@@ -515,37 +696,124 @@
return MediaCodec.createDecoderByType(mime);
}
+ // for video
private int countFrames(int video, int resetMode, int eosframe, Surface s)
throws Exception {
- int numframes = 0;
-
AssetFileDescriptor testFd = mResources.openRawResourceFd(video);
+ MediaExtractor extractor = new MediaExtractor();
+ extractor.setDataSource(testFd.getFileDescriptor(), testFd.getStartOffset(),
+ testFd.getLength());
+ extractor.selectTrack(0);
- MediaExtractor extractor;
- MediaCodec codec = null;
+ int numframes = decodeWithChecks(extractor, CHECKFLAG_RETURN_OUTPUTFRAMES
+ | CHECKFLAG_COMPAREINPUTOUTPUTPTSMATCH, resetMode, s,
+ eosframe, null, null);
+
+ extractor.release();
+ testFd.close();
+ return numframes;
+ }
+
+ // for audio
+ private int countSize(int audio, int resetMode, int eosframe)
+ throws Exception {
+ AssetFileDescriptor testFd = mResources.openRawResourceFd(audio);
+ MediaExtractor extractor = new MediaExtractor();
+ extractor.setDataSource(testFd.getFileDescriptor(), testFd.getStartOffset(),
+ testFd.getLength());
+ extractor.selectTrack(0);
+
+ // fails CHECKFLAG_COMPAREINPUTOUTPUTPTSMATCH
+ int outputSize = decodeWithChecks(extractor, CHECKFLAG_RETURN_OUTPUTSIZE, resetMode, null,
+ eosframe, null, null);
+
+ extractor.release();
+ testFd.close();
+ return outputSize;
+ }
+
+ private void testEOSBehavior(int movie, int stopatsample) throws Exception {
+ testEOSBehavior(movie, new int[] {stopatsample});
+ }
+
+ private void testEOSBehavior(int movie, int[] stopAtSample) throws Exception {
+ Surface s = null;
+ AssetFileDescriptor testFd = mResources.openRawResourceFd(movie);
+ MediaExtractor extractor = new MediaExtractor();
+ extractor.setDataSource(testFd.getFileDescriptor(), testFd.getStartOffset(),
+ testFd.getLength());
+ extractor.selectTrack(0); // consider variable looping on track
+ List<Long> outputChecksums = new ArrayList<Long>();
+ List<Long> outputTimestamps = new ArrayList<Long>();
+ Arrays.sort(stopAtSample);
+ int last = stopAtSample.length - 1;
+
+ // decode reference (longest sequence to stop at + 100) and
+ // store checksums/pts in outputChecksums and outputTimestamps
+ // (will fail CHECKFLAG_COMPAREINPUTOUTPUTSAMPLEMATCH)
+ decodeWithChecks(extractor,
+ CHECKFLAG_SETCHECKSUM | CHECKFLAG_SETPTS | CHECKFLAG_COMPAREINPUTOUTPUTPTSMATCH,
+ RESET_MODE_NONE, s,
+ stopAtSample[last] + 100, outputChecksums, outputTimestamps);
+
+ // decode stopAtSample requests in reverse order (longest to
+ // shortest) and compare to reference checksums/pts in
+ // outputChecksums and outputTimestamps
+ for (int i = last; i >= 0; --i) {
+ if (true) { // reposition extractor
+ extractor.seekTo(0, MediaExtractor.SEEK_TO_NEXT_SYNC);
+ } else { // create new extractor
+ extractor.release();
+ extractor = new MediaExtractor();
+ extractor.setDataSource(testFd.getFileDescriptor(),
+ testFd.getStartOffset(), testFd.getLength());
+ extractor.selectTrack(0); // consider variable looping on track
+ }
+ decodeWithChecks(extractor,
+ CHECKFLAG_COMPARECHECKSUM | CHECKFLAG_COMPAREPTS
+ | CHECKFLAG_COMPAREINPUTOUTPUTSAMPLEMATCH
+ | CHECKFLAG_COMPAREINPUTOUTPUTPTSMATCH,
+ RESET_MODE_NONE, s,
+ stopAtSample[i], outputChecksums, outputTimestamps);
+ }
+ extractor.release();
+ testFd.close();
+ }
+
+ private static final int CHECKFLAG_SETCHECKSUM = 1 << 0;
+ private static final int CHECKFLAG_COMPARECHECKSUM = 1 << 1;
+ private static final int CHECKFLAG_SETPTS = 1 << 2;
+ private static final int CHECKFLAG_COMPAREPTS = 1 << 3;
+ private static final int CHECKFLAG_COMPAREINPUTOUTPUTSAMPLEMATCH = 1 << 4;
+ private static final int CHECKFLAG_COMPAREINPUTOUTPUTPTSMATCH = 1 << 5;
+ private static final int CHECKFLAG_RETURN_OUTPUTFRAMES = 1 << 6;
+ private static final int CHECKFLAG_RETURN_OUTPUTSIZE = 1 << 7;
+
+ /**
+ * Decodes frames with parameterized checks and return values.
+ * The integer return can be selected through the checkFlags variable.
+ */
+ private static int decodeWithChecks(MediaExtractor extractor, int checkFlags, int resetMode,
+ Surface surface, int stopAtSample,
+ List<Long> outputChecksums, List<Long> outputTimestamps)
+ throws Exception {
+ int trackIndex = extractor.getSampleTrackIndex();
+ MediaFormat format = extractor.getTrackFormat(trackIndex);
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ boolean isAudio = mime.startsWith("audio/");
ByteBuffer[] codecInputBuffers;
ByteBuffer[] codecOutputBuffers;
- extractor = new MediaExtractor();
- extractor.setDataSource(testFd.getFileDescriptor(), testFd.getStartOffset(),
- testFd.getLength());
-
- MediaFormat format = extractor.getTrackFormat(0);
- String mime = format.getString(MediaFormat.KEY_MIME);
- boolean isAudio = mime.startsWith("audio/");
-
- codec = createDecoder(mime);
-
- assertNotNull("couldn't find codec", codec);
+ MediaCodec codec = createDecoder(mime);
Log.i("@@@@", "using codec: " + codec.getName());
- codec.configure(format, s /* surface */, null /* crypto */, 0 /* flags */);
+ codec.configure(format, surface, null /* crypto */, 0 /* flags */);
codec.start();
codecInputBuffers = codec.getInputBuffers();
codecOutputBuffers = codec.getOutputBuffers();
if (resetMode == RESET_MODE_RECONFIGURE) {
codec.stop();
- codec.configure(format, s /* surface */, null /* crypto */, 0 /* flags */);
+ codec.configure(format, surface, null /* crypto */, 0 /* flags */);
codec.start();
codecInputBuffers = codec.getInputBuffers();
codecOutputBuffers = codec.getOutputBuffers();
@@ -553,19 +821,28 @@
codec.flush();
}
- Log.i("@@@@", "format: " + format);
-
- extractor.selectTrack(0);
-
- // start decoding
- final long kTimeOutUs = 5000;
+ // start decode loop
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+
+ final long kTimeOutUs = 5000; // 5ms timeout
boolean sawInputEOS = false;
boolean sawOutputEOS = false;
int deadDecoderCounter = 0;
- int samplecounter = 0;
+ int samplenum = 0;
+ int numframes = 0;
+ int outputSize = 0;
+ int width = 0;
+ int height = 0;
+ boolean dochecksum = false;
ArrayList<Long> timestamps = new ArrayList<Long>();
+ if ((checkFlags & CHECKFLAG_SETPTS) != 0) {
+ outputTimestamps.clear();
+ }
+ if ((checkFlags & CHECKFLAG_SETCHECKSUM) != 0) {
+ outputChecksums.clear();
+ }
while (!sawOutputEOS && deadDecoderCounter < 100) {
+ // handle input
if (!sawInputEOS) {
int inputBufIndex = codec.dequeueInputBuffer(kTimeOutUs);
@@ -573,418 +850,286 @@
ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
int sampleSize =
- extractor.readSampleData(dstBuf, 0 /* offset */);
-
- long presentationTimeUs = 0;
+ extractor.readSampleData(dstBuf, 0 /* offset */);
+ long presentationTimeUs = extractor.getSampleTime();
+ boolean advanceDone = extractor.advance();
+ // int flags = extractor.getSampleFlags();
+ // Log.i("@@@@", "read sample " + samplenum + ":" +
+ // extractor.getSampleFlags()
+ // + " @ " + extractor.getSampleTime() + " size " +
+ // sampleSize);
+ assertEquals("extractor.advance() should match end of stream", sampleSize >= 0,
+ advanceDone);
if (sampleSize < 0) {
Log.d(TAG, "saw input EOS.");
sawInputEOS = true;
- sampleSize = 0;
+ assertEquals("extractor.readSampleData() must return -1 at end of stream",
+ -1, sampleSize);
+ assertEquals("extractor.getSampleTime() must return -1 at end of stream",
+ -1, presentationTimeUs);
+ sampleSize = 0; // required otherwise queueInputBuffer
+ // returns invalid.
} else {
- presentationTimeUs = extractor.getSampleTime();
- samplecounter++;
- if (samplecounter == eosframe) {
- sawInputEOS = true;
+ timestamps.add(presentationTimeUs);
+ samplenum++; // increment before comparing with stopAtSample
+ if (samplenum == stopAtSample) {
+ Log.d(TAG, "saw input EOS (stop at sample).");
+ sawInputEOS = true; // tag this sample as EOS
}
}
-
- timestamps.add(presentationTimeUs);
-
- int flags = extractor.getSampleFlags();
-
codec.queueInputBuffer(
inputBufIndex,
0 /* offset */,
sampleSize,
presentationTimeUs,
sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
-
- if (!sawInputEOS) {
- extractor.advance();
- }
+ } else {
+ assertEquals(
+ "codec.dequeueInputBuffer() unrecognized return value: " + inputBufIndex,
+ MediaCodec.INFO_TRY_AGAIN_LATER, inputBufIndex);
}
}
- int res = codec.dequeueOutputBuffer(info, kTimeOutUs);
+ // handle output
+ int outputBufIndex = codec.dequeueOutputBuffer(info, kTimeOutUs);
deadDecoderCounter++;
- if (res >= 0) {
- //Log.d(TAG, "got frame, size " + info.size + "/" + info.presentationTimeUs);
-
- // Some decoders output a 0-sized buffer at the end. Disregard those.
- if (info.size > 0) {
+ if (outputBufIndex >= 0) {
+ if (info.size > 0) { // Disregard 0-sized buffers at the end.
deadDecoderCounter = 0;
if (resetMode != RESET_MODE_NONE) {
- // once we've gotten some data out of the decoder, reset and start again
+ // once we've gotten some data out of the decoder, reset
+ // and start again
if (resetMode == RESET_MODE_RECONFIGURE) {
codec.stop();
- codec.configure(format, s /* surface */, null /* crypto */,
+ codec.configure(format, surface /* surface */, null /* crypto */,
0 /* flags */);
codec.start();
codecInputBuffers = codec.getInputBuffers();
codecOutputBuffers = codec.getOutputBuffers();
- } else /* resetMode == RESET_MODE_FLUSH */ {
+ } else if (resetMode == RESET_MODE_FLUSH) {
codec.flush();
+ } else {
+ fail("unknown resetMode: " + resetMode);
}
+ // restart at beginning, clear resetMode
resetMode = RESET_MODE_NONE;
extractor.seekTo(0, MediaExtractor.SEEK_TO_NEXT_SYNC);
sawInputEOS = false;
numframes = 0;
timestamps.clear();
+ if ((checkFlags & CHECKFLAG_SETPTS) != 0) {
+ outputTimestamps.clear();
+ }
+ if ((checkFlags & CHECKFLAG_SETCHECKSUM) != 0) {
+ outputChecksums.clear();
+ }
continue;
}
-
- if (isAudio) {
- // for audio, count the number of bytes that were decoded, not the number
- // of access units
- numframes += info.size;
- } else {
- // for video, count the number of video frames and check the timestamp
- numframes++;
- assertTrue("invalid timestamp", timestamps.remove(info.presentationTimeUs));
+ if ((checkFlags & CHECKFLAG_COMPAREPTS) != 0) {
+ assertTrue("number of frames (" + numframes
+ + ") exceeds number of reference timestamps",
+ numframes < outputTimestamps.size());
+ assertEquals("frame ts mismatch at frame " + numframes,
+ (long) outputTimestamps.get(numframes), info.presentationTimeUs);
+ } else if ((checkFlags & CHECKFLAG_SETPTS) != 0) {
+ outputTimestamps.add(info.presentationTimeUs);
}
+ if ((checkFlags & (CHECKFLAG_SETCHECKSUM | CHECKFLAG_COMPARECHECKSUM)) != 0) {
+ long sum = 0; // note: checksum is 0 if buffer format unrecognized
+ if (dochecksum) {
+ // TODO: add stride - right now just use info.size (as before)
+ //sum = checksum(codecOutputBuffers[outputBufIndex], width, height,
+ // stride);
+ ByteBuffer outputBuffer = codecOutputBuffers[outputBufIndex];
+ outputBuffer.position(info.offset);
+ sum = checksum(outputBuffer, info.size);
+ }
+ if ((checkFlags & CHECKFLAG_COMPARECHECKSUM) != 0) {
+ assertTrue("number of frames (" + numframes
+ + ") exceeds number of reference checksums",
+ numframes < outputChecksums.size());
+ Log.d(TAG, "orig checksum: " + outputChecksums.get(numframes)
+ + " new checksum: " + sum);
+ assertEquals("frame data mismatch at frame " + numframes,
+ (long) outputChecksums.get(numframes), sum);
+ } else if ((checkFlags & CHECKFLAG_SETCHECKSUM) != 0) {
+ outputChecksums.add(sum);
+ }
+ }
+ if ((checkFlags & CHECKFLAG_COMPAREINPUTOUTPUTPTSMATCH) != 0) {
+ assertTrue("output timestamp " + info.presentationTimeUs
+ + " without corresponding input timestamp"
+ , timestamps.remove(info.presentationTimeUs));
+ }
+ outputSize += info.size;
+ numframes++;
}
- int outputBufIndex = res;
+ // Log.d(TAG, "got frame, size " + info.size + "/" +
+ // info.presentationTimeUs +
+ // "/" + numframes + "/" + info.flags);
codec.releaseOutputBuffer(outputBufIndex, true /* render */);
-
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
Log.d(TAG, "saw output EOS.");
sawOutputEOS = true;
}
- } else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+ } else if (outputBufIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
codecOutputBuffers = codec.getOutputBuffers();
-
Log.d(TAG, "output buffers have changed.");
- } else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ } else if (outputBufIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
MediaFormat oformat = codec.getOutputFormat();
-
- Log.d(TAG, "output format has changed to " + oformat);
+ if (oformat.containsKey(MediaFormat.KEY_COLOR_FORMAT) &&
+ oformat.containsKey(MediaFormat.KEY_WIDTH) &&
+ oformat.containsKey(MediaFormat.KEY_HEIGHT)) {
+ int colorFormat = oformat.getInteger(MediaFormat.KEY_COLOR_FORMAT);
+ width = oformat.getInteger(MediaFormat.KEY_WIDTH);
+ height = oformat.getInteger(MediaFormat.KEY_HEIGHT);
+ dochecksum = isRecognizedFormat(colorFormat); // only checksum known raw
+ // buf formats
+ Log.d(TAG, "checksum fmt: " + colorFormat + " dim " + width + "x" + height);
+ } else {
+ dochecksum = false; // check with audio later
+ width = height = 0;
+ Log.d(TAG, "output format has changed to (unknown video) " + oformat);
+ }
} else {
- Log.d(TAG, "no output");
+ assertEquals(
+ "codec.dequeueOutputBuffer() unrecognized return index: "
+ + outputBufIndex,
+ MediaCodec.INFO_TRY_AGAIN_LATER, outputBufIndex);
}
}
-
codec.stop();
codec.release();
- testFd.close();
- return numframes;
+
+ assertTrue("last frame didn't have EOS", sawOutputEOS);
+ if ((checkFlags & CHECKFLAG_COMPAREINPUTOUTPUTSAMPLEMATCH) != 0) {
+ assertEquals("I!=O", samplenum, numframes);
+ if (stopAtSample != 0) {
+ assertEquals("did not stop with right number of frames", stopAtSample, numframes);
+ }
+ }
+ return (checkFlags & CHECKFLAG_RETURN_OUTPUTSIZE) != 0 ? outputSize :
+ (checkFlags & CHECKFLAG_RETURN_OUTPUTFRAMES) != 0 ? numframes :
+ 0;
}
public void testEOSBehaviorH264() throws Exception {
// this video has an I frame at 44
- testEOSBehavior(R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz, 44);
- testEOSBehavior(R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz, 45);
- testEOSBehavior(R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz, 55);
+ testEOSBehavior(R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz,
+ new int[] {44, 45, 55});
}
public void testEOSBehaviorH263() throws Exception {
// this video has an I frame every 12 frames.
- testEOSBehavior(R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz, 24);
- testEOSBehavior(R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz, 25);
- testEOSBehavior(R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz, 48);
- testEOSBehavior(R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz, 50);
+ testEOSBehavior(R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz,
+ new int[] {24, 25, 48, 50});
}
public void testEOSBehaviorMpeg4() throws Exception {
// this video has an I frame every 12 frames
- testEOSBehavior(R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz, 24);
- testEOSBehavior(R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz, 25);
- testEOSBehavior(R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz, 48);
- testEOSBehavior(R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz, 50);
- testEOSBehavior(R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz, 2);
+ testEOSBehavior(R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz,
+ new int[] {24, 25, 48, 50, 2});
}
public void testEOSBehaviorVP8() throws Exception {
// this video has an I frame at 46
- testEOSBehavior(R.raw.video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz, 46);
- testEOSBehavior(R.raw.video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz, 47);
- testEOSBehavior(R.raw.video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz, 57);
- testEOSBehavior(R.raw.video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz, 45);
+ testEOSBehavior(R.raw.video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz,
+ new int[] {46, 47, 57, 45});
}
public void testEOSBehaviorVP9() throws Exception {
// this video has an I frame at 44
- testEOSBehavior(R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_44100hz, 44);
- testEOSBehavior(R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_44100hz, 45);
- testEOSBehavior(R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_44100hz, 55);
- testEOSBehavior(R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_44100hz, 43);
- }
-
- private void testEOSBehavior(int movie, int stopatsample) throws Exception {
-
- int numframes = 0;
-
- long [] checksums = new long[stopatsample];
-
- AssetFileDescriptor testFd = mResources.openRawResourceFd(movie);
-
- MediaExtractor extractor;
- MediaCodec codec = null;
- ByteBuffer[] codecInputBuffers;
- ByteBuffer[] codecOutputBuffers;
-
- extractor = new MediaExtractor();
- extractor.setDataSource(testFd.getFileDescriptor(), testFd.getStartOffset(),
- testFd.getLength());
-
- MediaFormat format = extractor.getTrackFormat(0);
- String mime = format.getString(MediaFormat.KEY_MIME);
- boolean isAudio = mime.startsWith("audio/");
-
- codec = createDecoder(mime);
-
- assertNotNull("couldn't find codec", codec);
- Log.i("@@@@", "using codec: " + codec.getName());
- codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
- codec.start();
- codecInputBuffers = codec.getInputBuffers();
- codecOutputBuffers = codec.getOutputBuffers();
-
- extractor.selectTrack(0);
-
- // start decoding
- final long kTimeOutUs = 5000;
- MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
- boolean sawInputEOS = false;
- boolean sawOutputEOS = false;
- int deadDecoderCounter = 0;
- int samplenum = 0;
- boolean dochecksum = false;
- while (!sawOutputEOS && deadDecoderCounter < 100) {
- if (!sawInputEOS) {
- int inputBufIndex = codec.dequeueInputBuffer(kTimeOutUs);
-
- if (inputBufIndex >= 0) {
- ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
-
- int sampleSize =
- extractor.readSampleData(dstBuf, 0 /* offset */);
-// Log.i("@@@@", "read sample " + samplenum + ":" + extractor.getSampleFlags()
-// + " @ " + extractor.getSampleTime() + " size " + sampleSize);
- samplenum++;
-
- long presentationTimeUs = 0;
-
- if (sampleSize < 0 || samplenum >= (stopatsample + 100)) {
- Log.d(TAG, "saw input EOS.");
- sawInputEOS = true;
- sampleSize = 0;
- } else {
- presentationTimeUs = extractor.getSampleTime();
- }
-
- int flags = extractor.getSampleFlags();
-
- codec.queueInputBuffer(
- inputBufIndex,
- 0 /* offset */,
- sampleSize,
- presentationTimeUs,
- sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
-
- if (!sawInputEOS) {
- extractor.advance();
- }
- }
- }
-
- int res = codec.dequeueOutputBuffer(info, kTimeOutUs);
-
- deadDecoderCounter++;
- if (res >= 0) {
-
- // Some decoders output a 0-sized buffer at the end. Disregard those.
- if (info.size > 0) {
- deadDecoderCounter = 0;
-
- if (isAudio) {
- // for audio, count the number of bytes that were decoded, not the number
- // of access units
- numframes += info.size;
- } else {
- // for video, count the number of video frames
- long sum = dochecksum ? checksum(codecOutputBuffers[res], info.size) : 0;
- if (numframes < checksums.length) {
- checksums[numframes] = sum;
- }
- numframes++;
- }
- }
-// Log.d(TAG, "got frame, size " + info.size + "/" + info.presentationTimeUs +
-// "/" + numframes + "/" + info.flags);
-
- int outputBufIndex = res;
- codec.releaseOutputBuffer(outputBufIndex, true /* render */);
-
- if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
- Log.d(TAG, "saw output EOS.");
- sawOutputEOS = true;
- }
- } else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
- codecOutputBuffers = codec.getOutputBuffers();
-
- Log.d(TAG, "output buffers have changed.");
- } else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
- MediaFormat oformat = codec.getOutputFormat();
- int colorFormat = oformat.getInteger(MediaFormat.KEY_COLOR_FORMAT);
- dochecksum = isRecognizedFormat(colorFormat);
- Log.d(TAG, "output format has changed to " + oformat);
- } else {
- Log.d(TAG, "no output");
- }
- }
-
- codec.stop();
- codec.release();
- extractor.release();
-
-
- // We now have checksums for every frame.
- // Now decode again, but signal EOS right before an index frame, and ensure the frames
- // prior to that are the same.
-
- extractor = new MediaExtractor();
- extractor.setDataSource(testFd.getFileDescriptor(), testFd.getStartOffset(),
- testFd.getLength());
-
- codec = createDecoder(mime);
- codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
- codec.start();
- codecInputBuffers = codec.getInputBuffers();
- codecOutputBuffers = codec.getOutputBuffers();
-
- extractor.selectTrack(0);
-
- // start decoding
- info = new MediaCodec.BufferInfo();
- sawInputEOS = false;
- sawOutputEOS = false;
- deadDecoderCounter = 0;
- samplenum = 0;
- numframes = 0;
- dochecksum = false;
- while (!sawOutputEOS && deadDecoderCounter < 100) {
- if (!sawInputEOS) {
- int inputBufIndex = codec.dequeueInputBuffer(kTimeOutUs);
-
- if (inputBufIndex >= 0) {
- ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
-
- int sampleSize =
- extractor.readSampleData(dstBuf, 0 /* offset */);
-// Log.i("@@@@", "read sample " + samplenum + ":" + extractor.getSampleFlags()
-// + " @ " + extractor.getSampleTime() + " size " + sampleSize);
- samplenum++;
-
- long presentationTimeUs = extractor.getSampleTime();
-
- if (sampleSize < 0 || samplenum >= stopatsample) {
- Log.d(TAG, "saw input EOS.");
- sawInputEOS = true;
- if (sampleSize < 0) {
- sampleSize = 0;
- }
- }
-
- int flags = extractor.getSampleFlags();
-
- codec.queueInputBuffer(
- inputBufIndex,
- 0 /* offset */,
- sampleSize,
- presentationTimeUs,
- sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
-
- if (!sawInputEOS) {
- extractor.advance();
- }
- }
- }
-
- int res = codec.dequeueOutputBuffer(info, kTimeOutUs);
-
- deadDecoderCounter++;
- if (res >= 0) {
-
- // Some decoders output a 0-sized buffer at the end. Disregard those.
- if (info.size > 0) {
- deadDecoderCounter = 0;
-
- if (isAudio) {
- // for audio, count the number of bytes that were decoded, not the number
- // of access units
- numframes += info.size;
- } else {
- // for video, count the number of video frames
- long sum = dochecksum ? checksum(codecOutputBuffers[res], info.size) : 0;
- if (numframes < checksums.length) {
- assertEquals("frame data mismatch at frame " + numframes,
- checksums[numframes], sum);
- }
- numframes++;
- }
- }
-// Log.d(TAG, "got frame, size " + info.size + "/" + info.presentationTimeUs +
-// "/" + numframes + "/" + info.flags);
-
- int outputBufIndex = res;
- codec.releaseOutputBuffer(outputBufIndex, true /* render */);
-
- if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
- Log.d(TAG, "saw output EOS.");
- sawOutputEOS = true;
- }
- } else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
- codecOutputBuffers = codec.getOutputBuffers();
-
- Log.d(TAG, "output buffers have changed.");
- } else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
- MediaFormat oformat = codec.getOutputFormat();
- int colorFormat = oformat.getInteger(MediaFormat.KEY_COLOR_FORMAT);
- dochecksum = isRecognizedFormat(colorFormat);
- Log.d(TAG, "output format has changed to " + oformat);
- } else {
- Log.d(TAG, "no output");
- }
- }
-
- codec.stop();
- codec.release();
- extractor.release();
-
- assertEquals("I!=O", samplenum, numframes);
- assertTrue("last frame didn't have EOS", sawOutputEOS);
- assertEquals(stopatsample, numframes);
-
- testFd.close();
+ testEOSBehavior(R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_44100hz,
+ new int[] {44, 45, 55, 43});
}
/* from EncodeDecodeTest */
private static boolean isRecognizedFormat(int colorFormat) {
+ // Log.d(TAG, "color format: " + String.format("0x%08x", colorFormat));
switch (colorFormat) {
- // these are the formats we know how to handle for this test
+ // these are the formats we know how to handle for this test
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar:
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar:
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar:
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar:
case MediaCodecInfo.CodecCapabilities.COLOR_TI_FormatYUV420PackedSemiPlanar:
+ case MediaCodecInfo.CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar:
+ /*
+ * TODO: Check newer formats or ignore.
+ * OMX_SEC_COLOR_FormatNV12Tiled = 0x7FC00002
+ * OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka = 0x7FA30C03: N4/N7_2
+ * OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar32m = 0x7FA30C04: N5
+ */
return true;
default:
return false;
}
}
- private long checksum(ByteBuffer buf, int size) {
- assertTrue(size != 0);
- assertTrue(size <= buf.capacity());
+ private static long checksum(ByteBuffer buf, int size) {
+ int cap = buf.capacity();
+ assertTrue("checksum() params are invalid: size = " + size + " cap = " + cap,
+ size > 0 && size <= cap);
CRC32 crc = new CRC32();
- int pos = buf.position();
- buf.rewind();
- for (int i = 0; i < size; i++) {
- crc.update(buf.get());
+ if (buf.hasArray()) {
+ crc.update(buf.array(), buf.position() + buf.arrayOffset(), size);
+ } else {
+ int pos = buf.position();
+ final int rdsize = Math.min(4096, size);
+ byte bb[] = new byte[rdsize];
+ int chk;
+ for (int i = 0; i < size; i += chk) {
+ chk = Math.min(rdsize, size - i);
+ buf.get(bb, 0, chk);
+ crc.update(bb, 0, chk);
+ }
+ buf.position(pos);
}
- buf.position(pos);
+ return crc.getValue();
+ }
+
+ private static long checksum(ByteBuffer buf, int width, int height, int stride) {
+ int cap = buf.capacity();
+ assertTrue("checksum() params are invalid: w x h , s = "
+ + width + " x " + height + " , " + stride + " cap = " + cap,
+ width > 0 && width <= stride && height > 0 && height * stride <= cap);
+ // YUV 4:2:0 should generally have a data storage height 1.5x greater
+ // than the declared image height, representing the UV planes.
+ //
+ // We only check Y frame for now. Somewhat unknown with tiling effects.
+ //
+ //long tm = System.nanoTime();
+ final int lineinterval = 1; // line sampling frequency
+ CRC32 crc = new CRC32();
+ if (buf.hasArray()) {
+ byte b[] = buf.array();
+ int offs = buf.arrayOffset();
+ for (int i = 0; i < height; i += lineinterval) {
+ crc.update(b, i * stride + offs, width);
+ }
+ } else { // almost always ends up here due to direct buffers
+ int pos = buf.position();
+ if (true) { // this {} is 80x times faster than else {} below.
+ byte[] bb = new byte[width]; // local line buffer
+ for (int i = 0; i < height; i += lineinterval) {
+ buf.position(i * stride);
+ buf.get(bb, 0, width);
+ crc.update(bb, 0, width);
+ }
+ } else {
+ for (int i = 0; i < height; i += lineinterval) {
+ buf.position(i * stride);
+ for (int j = 0; j < width; ++j) {
+ crc.update(buf.get());
+ }
+ }
+ }
+ buf.position(pos);
+ }
+ //tm = System.nanoTime() - tm;
+ //Log.d(TAG, "checksum time " + tm);
return crc.getValue();
}
@@ -1073,8 +1218,9 @@
int outputBufIndex = res;
ByteBuffer buf = codecOutputBuffers[outputBufIndex];
+ buf.position(info.offset);
for (int i = 0; i < info.size; i += 2) {
- short sample = buf.getShort(i);
+ short sample = buf.getShort();
if (maxvalue < sample) {
maxvalue = sample;
}
diff --git a/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java b/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
index 6f1faf6..9e42414 100644
--- a/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
+++ b/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
@@ -1000,16 +1000,17 @@
x += cropLeft;
int testY, testU, testV;
+ int off = frameData.position();
if (semiPlanar) {
// Galaxy Nexus uses OMX_TI_COLOR_FormatYUV420PackedSemiPlanar
- testY = frameData.get(y * width + x) & 0xff;
- testU = frameData.get(width*height + 2*(y/2) * halfWidth + 2*(x/2)) & 0xff;
- testV = frameData.get(width*height + 2*(y/2) * halfWidth + 2*(x/2) + 1) & 0xff;
+ testY = frameData.get(off + y * width + x) & 0xff;
+ testU = frameData.get(off + width*height + 2*(y/2) * halfWidth + 2*(x/2)) & 0xff;
+ testV = frameData.get(off + width*height + 2*(y/2) * halfWidth + 2*(x/2) + 1) & 0xff;
} else {
// Nexus 10, Nexus 7 use COLOR_FormatYUV420Planar
- testY = frameData.get(y * width + x) & 0xff;
- testU = frameData.get(width*height + (y/2) * halfWidth + (x/2)) & 0xff;
- testV = frameData.get(width*height + halfWidth * (height / 2) +
+ testY = frameData.get(off + y * width + x) & 0xff;
+ testU = frameData.get(off + width*height + (y/2) * halfWidth + (x/2)) & 0xff;
+ testV = frameData.get(off + width*height + halfWidth * (height / 2) +
(y/2) * halfWidth + (x/2)) & 0xff;
}
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecTest.java b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
index 4b8abcd..86d03bf 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
@@ -120,7 +120,6 @@
assertNull(surface);
}
-
/**
* Tests:
* <br> signaling end-of-stream before any data is sent works
@@ -173,6 +172,57 @@
/**
* Tests:
+ * <br> stopping with buffers in flight doesn't crash or hang
+ */
+ public void testAbruptStop() {
+ // There appears to be a race, so run it several times with a short delay between runs
+ // to allow any previous activity to shut down.
+ for (int i = 0; i < 50; i++) {
+ Log.d(TAG, "testAbruptStop " + i);
+ doTestAbruptStop();
+ try { Thread.sleep(400); } catch (InterruptedException ignored) {}
+ }
+ }
+ private void doTestAbruptStop() {
+ MediaFormat format = createMediaFormat();
+ MediaCodec encoder = null;
+ InputSurface inputSurface = null;
+
+ try {
+ encoder = MediaCodec.createEncoderByType(MIME_TYPE);
+ encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+ inputSurface = new InputSurface(encoder.createInputSurface());
+ inputSurface.makeCurrent();
+ encoder.start();
+
+ int totalBuffers = encoder.getInputBuffers().length +
+ encoder.getOutputBuffers().length;
+ if (VERBOSE) Log.d(TAG, "Total buffers: " + totalBuffers);
+
+ // Submit several frames quickly, without draining the encoder output, to try to
+ // ensure that we've got some queued up when we call stop(). If we do too many
+ // we'll block in swapBuffers().
+ for (int i = 0; i < totalBuffers; i++) {
+ GLES20.glClearColor(0.0f, (i % 8) / 8.0f, 0.0f, 1.0f);
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+ inputSurface.swapBuffers();
+ }
+ Log.d(TAG, "stopping");
+ encoder.stop();
+ Log.d(TAG, "stopped");
+ } finally {
+ if (encoder != null) {
+ encoder.stop();
+ encoder.release();
+ }
+ if (inputSurface != null) {
+ inputSurface.release();
+ }
+ }
+ }
+
+ /**
+ * Tests:
* <br> dequeueInputBuffer() fails when encoder configured with an input Surface
*/
public void testDequeueSurface() {
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
index 0267497..03a5cfd 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
@@ -886,7 +886,7 @@
mMediaPlayer.setOnTimedTextListener(new MediaPlayer.OnTimedTextListener() {
@Override
public void onTimedText(MediaPlayer mp, TimedText text) {
- final int toleranceMs = 100;
+ final int toleranceMs = 150;
final int durationMs = 500;
int posMs = mMediaPlayer.getCurrentPosition();
if (text != null) {
diff --git a/tests/tests/media/src/android/media/cts/MediaScannerTest.java b/tests/tests/media/src/android/media/cts/MediaScannerTest.java
index 2dafdc5..f873fbc 100644
--- a/tests/tests/media/src/android/media/cts/MediaScannerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaScannerTest.java
@@ -367,6 +367,120 @@
assertTrue(new File(path2).delete());
}
+ static class MediaScanEntry {
+ MediaScanEntry(int r, String[] t) {
+ this.res = r;
+ this.tags = t;
+ }
+ int res;
+ String[] tags;
+ }
+
+ MediaScanEntry encodingtestfiles[] = {
+ new MediaScanEntry(R.raw.gb18030_1,
+ new String[] {"罗志祥", "2009年11月新歌", "罗志祥", "爱不单行(TV Version)", null} ),
+ new MediaScanEntry(R.raw.gb18030_2,
+ new String[] {"张杰", "明天过后", null, "明天过后", null} ),
+ new MediaScanEntry(R.raw.gb18030_3,
+ new String[] {"电视原声带", "格斗天王(限量精装版)(预购版)", null, "11.Open Arms.( cn808.net )", null} ),
+ new MediaScanEntry(R.raw.gb18030_4,
+ new String[] {"莫扎特", "黄金古典", "柏林爱乐乐团", "第25号交响曲", "莫扎特"} ),
+ new MediaScanEntry(R.raw.gb18030_5,
+ new String[] {"光良", "童话", "光良", "02.童话", "鍏夎壇"} ),
+ new MediaScanEntry(R.raw.gb18030_6,
+ new String[] {"张韶涵", "潘朵拉", "張韶涵", "隐形的翅膀", "王雅君"} ),
+ new MediaScanEntry(R.raw.gb18030_7,
+ new String[] {"五月天", "后青春期的诗", null, "突然好想你", null} ),
+ new MediaScanEntry(R.raw.gb18030_8,
+ new String[] {"周杰伦", "Jay", null, "反方向的钟", null} ),
+ new MediaScanEntry(R.raw.big5_1,
+ new String[] {"蘇永康", "So I Sing 08 Live", "蘇永康", "囍帖街", null} ),
+ new MediaScanEntry(R.raw.big5_2,
+ new String[] {"蘇永康", "So I Sing 08 Live", "蘇永康", "從不喜歡孤單一個 - 蘇永康/吳雨霏", null} ),
+ new MediaScanEntry(R.raw.cp1251_v1,
+ new String[] {"Екатерина Железнова", "Корабль игрушек", null, "Раз, два, три", null} ),
+ new MediaScanEntry(R.raw.cp1251_v1v2,
+ new String[] {"Мельница", "Перевал", null, "Королевна", null} ),
+ new MediaScanEntry(R.raw.cp1251_3,
+ new String[] {"Тату (tATu)", "200 По Встречной [Limited edi", null, "Я Сошла С Ума", null} ),
+ new MediaScanEntry(R.raw.cp1251_4,
+ new String[] {"Александр Розенбаум", "Философия любви", null, "Разговор в гостинице (Как жить без веры)", "А.Розенбаум"} ),
+ new MediaScanEntry(R.raw.cp1251_5,
+ new String[] {"Александр Розенбаум", "Философия любви", null, "Четвертиночка", "А.Розенбаум"} ),
+ new MediaScanEntry(R.raw.cp1251_6,
+ new String[] {"Александр Розенбаум", "Философия ремесла", null, "Ну, вот...", "А.Розенбаум"} ),
+ new MediaScanEntry(R.raw.shiftjis1,
+ new String[] {"", "", null, "中島敦「山月記」(第1回)", null} ),
+ new MediaScanEntry(R.raw.shiftjis2,
+ new String[] {"音人", "SoundEffects", null, "ファンファーレ", null} ),
+ new MediaScanEntry(R.raw.shiftjis3,
+ new String[] {"音人", "SoundEffects", null, "シンキングタイム", null} ),
+ new MediaScanEntry(R.raw.shiftjis4,
+ new String[] {"音人", "SoundEffects", null, "出題", null} ),
+ new MediaScanEntry(R.raw.shiftjis5,
+ new String[] {"音人", "SoundEffects", null, "時報", null} ),
+ new MediaScanEntry(R.raw.shiftjis6,
+ new String[] {"音人", "SoundEffects", null, "正解", null} ),
+ new MediaScanEntry(R.raw.shiftjis7,
+ new String[] {"音人", "SoundEffects", null, "残念", null} ),
+ new MediaScanEntry(R.raw.shiftjis8,
+ new String[] {"音人", "SoundEffects", null, "間違い", null} ),
+ new MediaScanEntry(R.raw.iso88591_1,
+ new String[] {"Mozart", "Best of Mozart", null, "Overtüre (Die Hochzeit des Figaro)", null} ),
+ new MediaScanEntry(R.raw.hebrew,
+ new String[] {"אריק סיני", "", null, "לי ולך", null } ),
+ new MediaScanEntry(R.raw.hebrew2,
+ new String[] {"הפרוייקט של עידן רייכל", "Untitled - 11-11-02 (9)", null, "בואי", null } )
+ };
+
+ public void testEncodingDetection() throws Exception {
+ for (int i = 0; i< encodingtestfiles.length; i++) {
+ MediaScanEntry entry = encodingtestfiles[i];
+ String path = mFileDir + "/" + "encodingtest" + i + ".mp3";
+ writeFile(entry.res, path);
+ }
+
+ startMediaScanAndWait();
+
+ String columns[] = {
+ MediaStore.Audio.Media.ARTIST,
+ MediaStore.Audio.Media.ALBUM,
+ MediaStore.Audio.Media.ALBUM_ARTIST,
+ MediaStore.Audio.Media.TITLE,
+ MediaStore.Audio.Media.COMPOSER
+ };
+ ContentResolver res = mContext.getContentResolver();
+ for (int i = 0; i< encodingtestfiles.length; i++) {
+ MediaScanEntry entry = encodingtestfiles[i];
+ String path = mFileDir + "/" + "encodingtest" + i + ".mp3";
+ Cursor c = res.query(MediaStore.Audio.Media.getContentUri("external"), columns,
+ MediaStore.Audio.Media.DATA + "=?", new String[] {path}, null);
+ assertNotNull("null cursor", c);
+ assertEquals("wrong number or results", 1, c.getCount());
+ assertTrue("failed to move cursor", c.moveToFirst());
+
+ for (int j =0; j < 5; j++) {
+ String expected = entry.tags[j];
+ if ("".equals(expected)) {
+ // empty entry in the table means an unset id3 tag that is filled in by
+ // the media scanner, e.g. by using "<unknown>". Since this may be localized,
+ // don't check it for any particular value.
+ assertNotNull("unexpected null entry " + i + " field " + j + "(" + path + ")",
+ c.getString(j));
+ } else {
+ assertEquals("mismatch on entry " + i + " field " + j + "(" + path + ")",
+ expected, c.getString(j));
+ }
+ }
+ // clean up
+ new File(path).delete();
+ res.delete(MediaStore.Audio.Media.getContentUri("external"),
+ MediaStore.Audio.Media.DATA + "=?", new String[] {path});
+
+ c.close();
+ }
+ }
+
private void startMediaScanAndWait() throws InterruptedException {
ScannerNotificationReceiver finishedReceiver = new ScannerNotificationReceiver(
Intent.ACTION_MEDIA_SCANNER_FINISHED);
diff --git a/tests/tests/media/src/android/media/cts/Vp8EncoderTest.java b/tests/tests/media/src/android/media/cts/Vp8EncoderTest.java
index 14e4055..8091d31 100644
--- a/tests/tests/media/src/android/media/cts/Vp8EncoderTest.java
+++ b/tests/tests/media/src/android/media/cts/Vp8EncoderTest.java
@@ -286,7 +286,7 @@
if (result >= 0) {
int outputBufIndex = result;
byte[] buffer = new byte[mBufferInfo.size];
- mOutputBuffers[outputBufIndex].rewind();
+ mOutputBuffers[outputBufIndex].position(mBufferInfo.offset);
mOutputBuffers[outputBufIndex].get(buffer, 0, mBufferInfo.size);
if ((outputFrameIndex == 0)
diff --git a/tests/tests/net/Android.mk b/tests/tests/net/Android.mk
index 7219fc4..9647df1 100644
--- a/tests/tests/net/Android.mk
+++ b/tests/tests/net/Android.mk
@@ -21,7 +21,7 @@
# and when built explicitly put it in the data partition
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_JAVA_LIBRARIES := android.test.runner voip-common
+LOCAL_JAVA_LIBRARIES := android.test.runner voip-common conscrypt
LOCAL_JNI_SHARED_LIBRARIES := libnativedns_jni
diff --git a/tests/tests/net/src/android/net/http/cts/X509TrustManagerExtensionsTest.java b/tests/tests/net/src/android/net/http/cts/X509TrustManagerExtensionsTest.java
new file mode 100644
index 0000000..9c0d774
--- /dev/null
+++ b/tests/tests/net/src/android/net/http/cts/X509TrustManagerExtensionsTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2012 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.net.http.cts;
+
+import android.net.http.X509TrustManagerExtensions;
+import android.util.Base64;
+
+import java.io.File;
+import java.io.ByteArrayInputStream;
+
+import java.security.KeyStore;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+import junit.framework.TestCase;
+
+import com.android.org.conscrypt.TrustedCertificateStore;
+import com.android.org.conscrypt.TrustManagerImpl;
+
+public class X509TrustManagerExtensionsTest extends TestCase {
+
+ public void testIsUserAddedCert() throws Exception {
+ final String testCert =
+ "MIICfjCCAeegAwIBAgIJAMefIzKHY5H4MA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV" +
+ "BAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEPMA0G" +
+ "A1UECgwGR2V3Z3VsMRMwEQYDVQQDDApnZXdndWwuY29tMB4XDTEzMTEwNTAwNDE0" +
+ "MFoXDTEzMTIwNTAwNDE0MFowWDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRYw" +
+ "FAYDVQQHDA1Nb3VudGFpbiBWaWV3MQ8wDQYDVQQKDAZHZXdndWwxEzARBgNVBAMM" +
+ "Cmdld2d1bC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKpc/I0Ss4sm" +
+ "yV2iX5xRMM7+XXAhiWrceGair4MpvDrGIa1kFj2phtx4IqTfDnNU7AhRJYkDYmJQ" +
+ "fUJ8i6F+I08uNiGVO4DtPJbZcBXg9ME9EMaJCslm995ueeNWSw1Ky8zM0tt4p+94" +
+ "BcXJ7PC3N2WgkvtE8xwNbaeUfhGPzJKXAgMBAAGjUDBOMB0GA1UdDgQWBBQQ/iW7" +
+ "JCkSI2sbn4nTBiZ9PSiO8zAfBgNVHSMEGDAWgBQQ/iW7JCkSI2sbn4nTBiZ9PSiO" +
+ "8zAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBABQBrUOWTCSIl3vkRR3w" +
+ "3bPzh3BpqDmxH9xe4rZr+MVKKjpGjY1z2m2EEtyNz3tbgVQym5+si00DUHFL0IP1" +
+ "SuRULmPyEpTBVbV+PA5Kc967ZcDgYt4JtdMcCeKbIFaU6r8oEYEL2PTlNZmgbunM" +
+ "pXktkhVvNxZeSa8yM9bPhXkN";
+
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ X509Certificate cert = (X509Certificate)cf.generateCertificate(
+ new ByteArrayInputStream(Base64.decode(testCert, Base64.DEFAULT)));
+
+ // Test without adding cert to keystore.
+ KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ X509TrustManagerExtensions tmeNegative =
+ new X509TrustManagerExtensions(new TrustManagerImpl(keyStore));
+ assertEquals(false, tmeNegative.isUserAddedCertificate(cert));
+
+ // Test with cert added to keystore.
+ final File DIR_TEMP = new File(System.getProperty("java.io.tmpdir"));
+ final File DIR_TEST = new File(DIR_TEMP, "test");
+ final File system = new File(DIR_TEST, "system-test");
+ final File added = new File(DIR_TEST, "added-test");
+ final File deleted = new File(DIR_TEST, "deleted-test");
+
+ TrustedCertificateStore tcs = new TrustedCertificateStore(system, added, deleted);
+ added.mkdirs();
+ tcs.installCertificate(cert);
+ X509TrustManagerExtensions tmePositive =
+ new X509TrustManagerExtensions(new TrustManagerImpl(keyStore, null, tcs));
+ assertEquals(true, tmePositive.isUserAddedCertificate(cert));
+ }
+}
diff --git a/tests/tests/permission/Android.mk b/tests/tests/permission/Android.mk
index 07f20d8..a32cc04 100644
--- a/tests/tests/permission/Android.mk
+++ b/tests/tests/permission/Android.mk
@@ -21,7 +21,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner guava
LOCAL_JNI_SHARED_LIBRARIES := libctspermission_jni
diff --git a/tests/tests/permission/jni/android_permission_cts_FileUtils.cpp b/tests/tests/permission/jni/android_permission_cts_FileUtils.cpp
index 272bbdc..8f32027 100644
--- a/tests/tests/permission/jni/android_permission_cts_FileUtils.cpp
+++ b/tests/tests/permission/jni/android_permission_cts_FileUtils.cpp
@@ -25,6 +25,9 @@
#include <grp.h>
#include <pwd.h>
#include <string.h>
+#include <ScopedLocalRef.h>
+#include <ScopedPrimitiveArray.h>
+#include <ScopedUtfChars.h>
static jfieldID gFileStatusDevFieldID;
static jfieldID gFileStatusInoFieldID;
@@ -46,14 +49,15 @@
* Copied from hidden API: frameworks/base/core/jni/android_os_FileUtils.cpp
*/
-jboolean android_permission_cts_FileUtils_getFileStatus(JNIEnv* env, jobject thiz,
- jstring path, jobject fileStatus, jboolean statLinks)
+jboolean android_permission_cts_FileUtils_getFileStatus(JNIEnv* env,
+ jobject /* thiz */, jstring path, jobject fileStatus, jboolean statLinks)
{
- const char* pathStr = env->GetStringUTFChars(path, NULL);
+ ScopedUtfChars cPath(env, path);
jboolean ret = false;
struct stat s;
- int res = statLinks == true ? lstat(pathStr, &s) : stat(pathStr, &s);
+ int res = statLinks == true ? lstat(cPath.c_str(), &s)
+ : stat(cPath.c_str(), &s);
if (res == 0) {
ret = true;
@@ -73,20 +77,18 @@
}
}
- env->ReleaseStringUTFChars(path, pathStr);
-
return ret;
}
-jstring android_permission_cts_FileUtils_getUserName(JNIEnv* env, jobject thiz,
- jint uid)
+jstring android_permission_cts_FileUtils_getUserName(JNIEnv* env,
+ jobject /* thiz */, jint uid)
{
struct passwd *pwd = getpwuid(uid);
return env->NewStringUTF(pwd->pw_name);
}
-jstring android_permission_cts_FileUtils_getGroupName(JNIEnv* env, jobject thiz,
- jint gid)
+jstring android_permission_cts_FileUtils_getGroupName(JNIEnv* env,
+ jobject /* thiz */, jint gid)
{
struct group *grp = getgrgid(gid);
return env->NewStringUTF(grp->gr_name);
@@ -94,42 +96,106 @@
static jboolean isPermittedCapBitSet(JNIEnv* env, jstring path, size_t capId)
{
- const char* pathStr = env->GetStringUTFChars(path, NULL);
- jboolean ret = false;
-
struct vfs_cap_data capData;
memset(&capData, 0, sizeof(capData));
- ssize_t result = getxattr(pathStr, XATTR_NAME_CAPS, &capData,
+ ScopedUtfChars cPath(env, path);
+ ssize_t result = getxattr(cPath.c_str(), XATTR_NAME_CAPS, &capData,
sizeof(capData));
- if (result > 0) {
- ret = (capData.data[CAP_TO_INDEX(capId)].permitted &
- CAP_TO_MASK(capId)) != 0;
- ALOGD("isPermittedCapBitSet(): getxattr(\"%s\") call succeeded, "
- "cap bit %u %s",
- pathStr, capId, ret ? "set" : "unset");
- } else {
- ALOGD("isPermittedCapBitSet(): getxattr(\"%s\") call failed: "
- "return %d (error: %s (%d))\n",
- pathStr, result, strerror(errno), errno);
+ if (result <= 0)
+ {
+ ALOGD("isPermittedCapBitSet(): getxattr(\"%s\") call failed: "
+ "return %d (error: %s (%d))\n",
+ cPath.c_str(), result, strerror(errno), errno);
+ return false;
}
- env->ReleaseStringUTFChars(path, pathStr);
- return ret;
+ return (capData.data[CAP_TO_INDEX(capId)].permitted &
+ CAP_TO_MASK(capId)) != 0;
}
jboolean android_permission_cts_FileUtils_hasSetUidCapability(JNIEnv* env,
- jobject clazz, jstring path)
+ jobject /* clazz */, jstring path)
{
return isPermittedCapBitSet(env, path, CAP_SETUID);
}
jboolean android_permission_cts_FileUtils_hasSetGidCapability(JNIEnv* env,
- jobject clazz, jstring path)
+ jobject /* clazz */, jstring path)
{
return isPermittedCapBitSet(env, path, CAP_SETGID);
}
+static bool throwNamedException(JNIEnv* env, const char* className,
+ const char* message)
+{
+ ScopedLocalRef<jclass> eClazz(env, env->FindClass(className));
+ if (eClazz.get() == NULL)
+ {
+ ALOGE("throwNamedException(): failed to find class %s, cannot throw",
+ className);
+ return false;
+ }
+
+ env->ThrowNew(eClazz.get(), message);
+ return true;
+}
+
+// fill vfs_cap_data's permitted caps given a Java int[] of cap ids
+static bool fillPermittedCaps(vfs_cap_data* capData, JNIEnv* env, jintArray capIds)
+{
+ ScopedIntArrayRO cCapIds(env, capIds);
+ const size_t capCount = cCapIds.size();
+
+ for (size_t i = 0; i < capCount; ++i)
+ {
+ const jint capId = cCapIds[i];
+ if (!cap_valid(capId))
+ {
+ char message[64];
+ snprintf(message, sizeof(message),
+ "capability id %d out of valid range", capId);
+ throwNamedException(env, "java/lang/IllegalArgumentException",
+ message);
+
+ return false;
+ }
+ capData->data[CAP_TO_INDEX(capId)].permitted |= CAP_TO_MASK(capId);
+ }
+ return true;
+}
+
+jboolean android_permission_cts_FileUtils_CapabilitySet_fileHasOnly(JNIEnv* env,
+ jobject /* clazz */, jstring path, jintArray capIds)
+{
+ struct vfs_cap_data expectedCapData;
+ memset(&expectedCapData, 0, sizeof(expectedCapData));
+
+ expectedCapData.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE;
+ if (!fillPermittedCaps(&expectedCapData, env, capIds))
+ {
+ // exception thrown
+ return false;
+ }
+
+ struct vfs_cap_data actualCapData;
+ memset(&actualCapData, 0, sizeof(actualCapData));
+
+ ScopedUtfChars cPath(env, path);
+ ssize_t result = getxattr(cPath.c_str(), XATTR_NAME_CAPS, &actualCapData,
+ sizeof(actualCapData));
+ if (result <= 0)
+ {
+ ALOGD("fileHasOnly(): getxattr(\"%s\") call failed: "
+ "return %d (error: %s (%d))\n",
+ cPath.c_str(), result, strerror(errno), errno);
+ return false;
+ }
+
+ return (memcmp(&expectedCapData, &actualCapData,
+ sizeof(struct vfs_cap_data)) == 0);
+}
+
static JNINativeMethod gMethods[] = {
{ "getFileStatus", "(Ljava/lang/String;Landroid/permission/cts/FileUtils$FileStatus;Z)Z",
(void *) android_permission_cts_FileUtils_getFileStatus },
@@ -143,6 +209,11 @@
(void *) android_permission_cts_FileUtils_hasSetGidCapability },
};
+static JNINativeMethod gCapabilitySetMethods[] = {
+ { "fileHasOnly", "(Ljava/lang/String;[I)Z",
+ (void *) android_permission_cts_FileUtils_CapabilitySet_fileHasOnly },
+};
+
int register_android_permission_cts_FileUtils(JNIEnv* env)
{
jclass clazz = env->FindClass("android/permission/cts/FileUtils");
@@ -161,6 +232,16 @@
gFileStatusMtimeFieldID = env->GetFieldID(fileStatusClass, "mtime", "J");
gFileStatusCtimeFieldID = env->GetFieldID(fileStatusClass, "ctime", "J");
- return env->RegisterNatives(clazz, gMethods,
- sizeof(gMethods) / sizeof(JNINativeMethod));
+ jint result = env->RegisterNatives(clazz, gMethods,
+ sizeof(gMethods) / sizeof(JNINativeMethod));
+ if (result)
+ {
+ return result;
+ }
+
+ // register FileUtils.CapabilitySet native methods
+ jclass capClazz = env->FindClass("android/permission/cts/FileUtils$CapabilitySet");
+
+ return env->RegisterNatives(capClazz, gCapabilitySetMethods,
+ sizeof(gCapabilitySetMethods) / sizeof(JNINativeMethod));
}
diff --git a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
index 83f2a36..27c7215 100644
--- a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
@@ -44,6 +44,8 @@
import java.util.List;
import java.util.Set;
+import libcore.io.OsConstants;
+
/**
* Verify certain permissions on the filesystem
*
@@ -823,6 +825,30 @@
assertFileOwnedByGroup(f, "system");
}
+ public void testFileHasOnlyCapsThrowsOnInvalidCaps() throws Exception {
+ try {
+ // Ensure negative cap id fails.
+ new FileUtils.CapabilitySet()
+ .add(-1)
+ .fileHasOnly("/system/bin/run-as");
+ fail();
+ }
+ catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ // Ensure too-large cap throws.
+ new FileUtils.CapabilitySet()
+ .add(OsConstants.CAP_LAST_CAP + 1)
+ .fileHasOnly("/system/bin/run-as");
+ fail();
+ }
+ catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
/**
* Test that the /system/bin/run-as command has setuid and setgid
* attributes set on the file. If these calls fail, debugger
@@ -845,6 +871,12 @@
// ensure file has setuid/setgid enabled
assertTrue(FileUtils.hasSetUidCapability(filename));
assertTrue(FileUtils.hasSetGidCapability(filename));
+
+ // ensure file has *only* setuid/setgid attributes enabled
+ assertTrue(new FileUtils.CapabilitySet()
+ .add(OsConstants.CAP_SETUID)
+ .add(OsConstants.CAP_SETGID)
+ .fileHasOnly("/system/bin/run-as"));
}
private static Set<File>
diff --git a/tests/tests/permission/src/android/permission/cts/FileUtils.java b/tests/tests/permission/src/android/permission/cts/FileUtils.java
index 9cd4999..657c783 100644
--- a/tests/tests/permission/src/android/permission/cts/FileUtils.java
+++ b/tests/tests/permission/src/android/permission/cts/FileUtils.java
@@ -16,6 +16,13 @@
* limitations under the License.
*/
+import com.google.common.primitives.Ints;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import libcore.io.OsConstants;
+
/** Bits and pieces copied from hidden API of android.os.FileUtils. */
public class FileUtils {
@@ -82,6 +89,27 @@
}
}
+ public static class CapabilitySet {
+
+ private final Set<Integer> mCapabilities = new HashSet<Integer>();
+
+ public CapabilitySet add(int capability) {
+ if ((capability < 0) || (capability > OsConstants.CAP_LAST_CAP)) {
+ throw new IllegalArgumentException(String.format(
+ "capability id %d out of valid range", capability));
+ }
+ mCapabilities.add(capability);
+ return this;
+ }
+
+ private native static boolean fileHasOnly(String path,
+ int[] capabilities);
+
+ public boolean fileHasOnly(String path) {
+ return fileHasOnly(path, Ints.toArray(mCapabilities));
+ }
+ }
+
/**
* @param path of the file to stat
* @param status object to set the fields on
diff --git a/tests/tests/print/Android.mk b/tests/tests/print/Android.mk
new file mode 100644
index 0000000..d9fcba6
--- /dev/null
+++ b/tests/tests/print/Android.mk
@@ -0,0 +1,33 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+ src/android/print/cts/IPrivilegedOperations.aidl
+
+LOCAL_PACKAGE_NAME := CtsPrintTestCases
+
+LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ctstestrunner ub-uiautomator
+
+# This test runner sets up/cleans up the device before/after running the tests.
+LOCAL_CTS_TEST_RUNNER := com.android.cts.tradefed.testtype.PrintTestRunner
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/print/AndroidManifest.xml b/tests/tests/print/AndroidManifest.xml
new file mode 100644
index 0000000..82715cb
--- /dev/null
+++ b/tests/tests/print/AndroidManifest.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.print">
+
+ <application android:allowBackup="false" >
+
+ <uses-library android:name="android.test.runner"/>
+
+ <activity android:name="android.print.cts.PrintDocumentAdapterContractActivity"/>
+
+ <service
+ android:name="android.print.cts.services.FirstPrintService"
+ android:permission="android.permission.BIND_PRINT_SERVICE">
+ <intent-filter>
+ <action android:name="android.printservice.PrintService" />
+ </intent-filter>
+ <meta-data
+ android:name="android.printservice"
+ android:resource="@xml/printservice">
+ </meta-data>
+ </service>
+
+ <service
+ android:name="android.print.cts.services.SecondPrintService"
+ android:permission="android.permission.BIND_PRINT_SERVICE">
+ <intent-filter>
+ <action android:name="android.printservice.PrintService" />
+ </intent-filter>
+ <meta-data
+ android:name="android.printservice"
+ android:resource="@xml/printservice">
+ </meta-data>
+ </service>
+
+ <activity
+ android:name="android.print.cts.services.SettingsActivity"
+ android:permission="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"
+ android:exported="true">
+ </activity>
+
+ <activity
+ android:name="android.print.cts.services.AddPrintersActivity"
+ android:permission="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"
+ android:exported="true">
+ </activity>
+
+ <activity
+ android:name="android.print.cts.services.CustomPrintOptionsActivity"
+ android:permission="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"
+ android:exported="true">
+ </activity>
+
+ </application>
+
+ <instrumentation android:name="android.support.test.uiautomator.UiAutomatorInstrumentationTestRunner"
+ android:targetPackage="com.android.cts.print"
+ android:label="Tests for the print APIs."/>
+
+</manifest>
diff --git a/tests/tests/print/res/values/strings.xml b/tests/tests/print/res/values/strings.xml
new file mode 100644
index 0000000..6d869e9
--- /dev/null
+++ b/tests/tests/print/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+
+ <string name="resolution_200x200">200x200</string>
+ <string name="resolution_300x300">300x300</string>
+ <string name="resolution_600x600">600x600</string>
+
+</resources>
diff --git a/tests/tests/print/res/xml/printservice.xml b/tests/tests/print/res/xml/printservice.xml
new file mode 100644
index 0000000..5579b81
--- /dev/null
+++ b/tests/tests/print/res/xml/printservice.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<print-service xmlns:android="http://schemas.android.com/apk/res/android"
+ android:settingsActivity="android.print.services.SettingsActivity"
+ android:addPrintersActivity="android.print.services.AddPrintersActivity"
+ android:advancedPrintOptionsActivity="android.print.services.CustomPrintOptionsActivity"/>
diff --git a/tests/tests/print/src/android/print/cts/BasePrintTest.java b/tests/tests/print/src/android/print/cts/BasePrintTest.java
new file mode 100644
index 0000000..c1973ca
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/BasePrintTest.java
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.cts;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.os.SystemClock;
+import android.print.PageRange;
+import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintDocumentAdapter.LayoutResultCallback;
+import android.print.PrintDocumentAdapter.WriteResultCallback;
+import android.print.PrintManager;
+import android.print.PrinterId;
+import android.print.cts.services.PrintServiceCallbacks;
+import android.print.cts.services.PrinterDiscoverySessionCallbacks;
+import android.print.cts.services.StubbablePrinterDiscoverySession;
+import android.printservice.PrintJob;
+import android.printservice.PrintService;
+import android.support.test.uiautomator.UiAutomatorTestCase;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiSelector;
+import android.util.DisplayMetrics;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.mockito.InOrder;
+import org.mockito.stubbing.Answer;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * This is the base class for print tests.
+ */
+public abstract class BasePrintTest extends UiAutomatorTestCase {
+
+ private static final long OPERATION_TIMEOUT = 10000;
+
+ private static final String ARG_PRIVILEGED_OPS = "ARG_PRIVILEGED_OPS";
+
+ private static final String PRINT_SPOOLER_PACKAGE_NAME = "com.android.printspooler";
+
+ protected static final String PRINT_JOB_NAME = "Test";
+
+ private PrintDocumentAdapterContractActivity mActivity;
+
+ private Locale mOldLocale;
+
+ private CallCounter mLayoutCallCounter;
+ private CallCounter mWriteCallCounter;
+ private CallCounter mFinishCallCounter;
+ private CallCounter mPrintJobQueuedCallCounter;
+
+ @Override
+ public void setUp() throws Exception {
+ // Make sure we start with a clean slate.
+ clearPrintSpoolerData();
+
+ // Workaround for dexmaker bug: https://code.google.com/p/dexmaker/issues/detail?id=2
+ // Dexmaker is used by mockito.
+ System.setProperty("dexmaker.dexcache", getInstrumentation()
+ .getTargetContext().getCacheDir().getPath());
+
+ // Set to US locale.
+ Resources resources = getInstrumentation().getTargetContext().getResources();
+ Configuration oldConfiguration = resources.getConfiguration();
+ if (!oldConfiguration.locale.equals(Locale.US)) {
+ mOldLocale = oldConfiguration.locale;
+ DisplayMetrics displayMetrics = resources.getDisplayMetrics();
+ Configuration newConfiguration = new Configuration(oldConfiguration);
+ newConfiguration.locale = Locale.US;
+ resources.updateConfiguration(newConfiguration, displayMetrics);
+ }
+
+ // Initialize the latches.
+ mLayoutCallCounter = new CallCounter();
+ mFinishCallCounter = new CallCounter();
+ mWriteCallCounter = new CallCounter();
+ mFinishCallCounter = new CallCounter();
+ mPrintJobQueuedCallCounter = new CallCounter();
+
+ // Create the activity for the right locale.
+ createActivity();
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ // Done with the activity.
+ getActivity().finish();
+
+ // Restore the locale if needed.
+ if (mOldLocale != null) {
+ Resources resources = getInstrumentation().getTargetContext().getResources();
+ DisplayMetrics displayMetrics = resources.getDisplayMetrics();
+ Configuration newConfiguration = new Configuration(resources.getConfiguration());
+ newConfiguration.locale = mOldLocale;
+ mOldLocale = null;
+ resources.updateConfiguration(newConfiguration, displayMetrics);
+ }
+
+ // Make sure the spooler is cleaned.
+ clearPrintSpoolerData();
+ }
+
+ protected void print(final PrintDocumentAdapter adapter) {
+ // Initiate printing as if coming from the app.
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ PrintManager printManager = (PrintManager) getActivity()
+ .getSystemService(Context.PRINT_SERVICE);
+ printManager.print("Print job", adapter, null);
+ }
+ });
+ }
+
+ protected void onLayoutCalled() {
+ mLayoutCallCounter.call();
+ }
+
+ protected void onWriteCalled() {
+ mWriteCallCounter.call();
+ }
+
+ protected void onFinishCalled() {
+ mFinishCallCounter.call();
+ }
+
+ protected void onPrintJobQueuedCalled() {
+ mPrintJobQueuedCallCounter.call();
+ }
+
+ protected void waitForServiceOnPrintJobQueuedCallbackCalled() {
+ waitForCallbackCallCount(mPrintJobQueuedCallCounter, 1,
+ "Did not get expected call to onPrintJobQueued.");
+ }
+
+ protected void waitForAdapterCallbackFinish() {
+ waitForCallbackCallCount(mFinishCallCounter, 1,
+ "Did not get expected call to finish.");
+ }
+
+ protected void waitForLayoutAdapterCallbackCount(int count) {
+ waitForCallbackCallCount(mLayoutCallCounter, count,
+ "Did not get expected call to layout.");
+ }
+
+ protected void waitForWriteForAdapterCallback() {
+ waitForCallbackCallCount(mWriteCallCounter, 1, "Did not get expected call to write.");
+ }
+
+ private void waitForCallbackCallCount(CallCounter counter, int count, String message) {
+ try {
+ counter.waitForCount(count, OPERATION_TIMEOUT);
+ } catch (TimeoutException te) {
+ fail(message);
+ }
+ }
+
+ protected void selectPrinter(String printerName) throws UiObjectNotFoundException {
+ UiObject destinationSpinner = new UiObject(new UiSelector().resourceId(
+ "com.android.printspooler:id/destination_spinner"));
+ destinationSpinner.click();
+ UiObject printerOption = new UiObject(new UiSelector().text(printerName));
+ printerOption.click();
+ }
+
+ protected void changeOrientation(String orientation) throws UiObjectNotFoundException {
+ UiObject orientationSpinner = new UiObject(new UiSelector().resourceId(
+ "com.android.printspooler:id/orientation_spinner"));
+ orientationSpinner.click();
+ UiObject orientationOption = new UiObject(new UiSelector().text(orientation));
+ orientationOption.click();
+ }
+
+ protected void changeMediaSize(String mediaSize) throws UiObjectNotFoundException {
+ UiObject mediaSizeSpinner = new UiObject(new UiSelector().resourceId(
+ "com.android.printspooler:id/paper_size_spinner"));
+ mediaSizeSpinner.click();
+ UiObject mediaSizeOption = new UiObject(new UiSelector().text(mediaSize));
+ mediaSizeOption.click();
+ }
+
+ protected void changeColor(String color) throws UiObjectNotFoundException {
+ UiObject colorSpinner = new UiObject(new UiSelector().resourceId(
+ "com.android.printspooler:id/color_spinner"));
+ colorSpinner.click();
+ UiObject colorOption = new UiObject(new UiSelector().text(color));
+ colorOption.click();
+ }
+
+ protected void clickPrintButton() throws UiObjectNotFoundException {
+ UiObject printButton = new UiObject(new UiSelector().resourceId(
+ "com.android.printspooler:id/print_button"));
+ printButton.click();
+ }
+
+ protected PrintDocumentAdapterContractActivity getActivity() {
+ return mActivity;
+ }
+
+ private void createActivity() {
+ mActivity = launchActivity(
+ getInstrumentation().getTargetContext().getPackageName(),
+ PrintDocumentAdapterContractActivity.class, null);
+ }
+
+ protected void clearPrintSpoolerData() throws Exception {
+ IPrivilegedOperations privilegedOps = IPrivilegedOperations.Stub.asInterface(
+ getParams().getBinder(ARG_PRIVILEGED_OPS));
+ privilegedOps.clearApplicationUserData(PRINT_SPOOLER_PACKAGE_NAME);
+ }
+
+ protected void verifyLayoutCall(InOrder inOrder, PrintDocumentAdapter mock,
+ PrintAttributes oldAttributes, PrintAttributes newAttributes,
+ final boolean forPreview) {
+ inOrder.verify(mock).onLayout(eq(oldAttributes), eq(newAttributes),
+ any(CancellationSignal.class), any(LayoutResultCallback.class), argThat(
+ new BaseMatcher<Bundle>() {
+ @Override
+ public boolean matches(Object item) {
+ Bundle bundle = (Bundle) item;
+ return forPreview == bundle.getBoolean(
+ PrintDocumentAdapter.EXTRA_PRINT_PREVIEW);
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ /* do nothing */
+ }
+ }));
+ }
+
+ protected PrintDocumentAdapter createMockPrintDocumentAdapter(Answer<Void> layoutAnswer,
+ Answer<Void> writeAnswer, Answer<Void> finishAnswer) {
+ // Create a mock print adapter.
+ PrintDocumentAdapter adapter = mock(PrintDocumentAdapter.class);
+ if (layoutAnswer != null) {
+ doAnswer(layoutAnswer).when(adapter).onLayout(any(PrintAttributes.class),
+ any(PrintAttributes.class), any(CancellationSignal.class),
+ any(LayoutResultCallback.class), any(Bundle.class));
+ }
+ if (writeAnswer != null) {
+ doAnswer(writeAnswer).when(adapter).onWrite(any(PageRange[].class),
+ any(ParcelFileDescriptor.class), any(CancellationSignal.class),
+ any(WriteResultCallback.class));
+ }
+ if (finishAnswer != null) {
+ doAnswer(finishAnswer).when(adapter).onFinish();
+ }
+ return adapter;
+ }
+
+ @SuppressWarnings("unchecked")
+ protected PrinterDiscoverySessionCallbacks createMockPrinterDiscoverySessionCallbacks(
+ Answer<Void> onStartPrinterDiscovery, Answer<Void> onStopPrinterDiscovery,
+ Answer<Void> onValidatePrinters, Answer<Void> onStartPrinterStateTracking,
+ Answer<Void> onStopPrinterStateTracking, Answer<Void> onDestroy) {
+ PrinterDiscoverySessionCallbacks callbacks = mock(PrinterDiscoverySessionCallbacks.class);
+
+ doCallRealMethod().when(callbacks).setSession(any(StubbablePrinterDiscoverySession.class));
+ when(callbacks.getSession()).thenCallRealMethod();
+
+ if (onStartPrinterDiscovery != null) {
+ doAnswer(onStartPrinterDiscovery).when(callbacks).onStartPrinterDiscovery(
+ any(List.class));
+ }
+ if (onStopPrinterDiscovery != null) {
+ doAnswer(onStopPrinterDiscovery).when(callbacks).onStopPrinterDiscovery();
+ }
+ if (onValidatePrinters != null) {
+ doAnswer(onValidatePrinters).when(callbacks).onValidatePrinters(
+ any(List.class));
+ }
+ if (onStartPrinterStateTracking != null) {
+ doAnswer(onStartPrinterStateTracking).when(callbacks).onStartPrinterStateTracking(
+ any(PrinterId.class));
+ }
+ if (onStopPrinterStateTracking != null) {
+ doAnswer(onStopPrinterStateTracking).when(callbacks).onStopPrinterStateTracking(
+ any(PrinterId.class));
+ }
+ if (onDestroy != null) {
+ doAnswer(onDestroy).when(callbacks).onDestroy();
+ }
+
+ return callbacks;
+ }
+
+ protected PrintServiceCallbacks createMockPrintServiceCallbacks(
+ Answer<PrinterDiscoverySessionCallbacks> onCreatePrinterDiscoverySessionCallbacks,
+ Answer<Void> onPrintJobQueued, Answer<Void> onRequestCancelPrintJob) {
+ final PrintServiceCallbacks service = mock(PrintServiceCallbacks.class);
+
+ doCallRealMethod().when(service).setService(any(PrintService.class));
+ when(service.getService()).thenCallRealMethod();
+
+ if (onCreatePrinterDiscoverySessionCallbacks != null) {
+ doAnswer(onCreatePrinterDiscoverySessionCallbacks).when(service)
+ .onCreatePrinterDiscoverySessionCallbacks();
+ }
+ if (onPrintJobQueued != null) {
+ doAnswer(onPrintJobQueued).when(service).onPrintJobQueued(any(PrintJob.class));
+ }
+ if (onRequestCancelPrintJob != null) {
+ doAnswer(onRequestCancelPrintJob).when(service).onRequestCancelPrintJob(
+ any(PrintJob.class));
+ }
+
+ return service;
+ }
+
+ protected final class CallCounter {
+ private final Object mLock = new Object();
+
+ private int mCallCount;
+
+ public void call() {
+ synchronized (mLock) {
+ mCallCount++;
+ }
+ }
+
+ public void waitForCount(int count, long timeoutMIllis) throws TimeoutException {
+ synchronized (mLock) {
+ final long startTimeMillis = SystemClock.uptimeMillis();
+ while (mCallCount < count) {
+ try {
+ final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+ final long remainingTimeMillis = timeoutMIllis - elapsedTimeMillis;
+ if (remainingTimeMillis <= 0) {
+ throw new TimeoutException();
+ }
+ mLock.wait(timeoutMIllis);
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/tests/print/src/android/print/cts/IPrivilegedOperations.aidl b/tests/tests/print/src/android/print/cts/IPrivilegedOperations.aidl
new file mode 100644
index 0000000..93c8c3e
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/IPrivilegedOperations.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.cts;
+
+interface IPrivilegedOperations {
+ boolean clearApplicationUserData(String packageName);
+}
diff --git a/tests/tests/print/src/android/print/cts/PageRangeAdjustmentTest.java b/tests/tests/print/src/android/print/cts/PageRangeAdjustmentTest.java
new file mode 100644
index 0000000..cf28800
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/PageRangeAdjustmentTest.java
@@ -0,0 +1,510 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.cts;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.never;
+
+import android.os.ParcelFileDescriptor;
+import android.print.PageRange;
+import android.print.PrintAttributes;
+import android.print.PrintAttributes.Margins;
+import android.print.PrintAttributes.MediaSize;
+import android.print.PrintAttributes.Resolution;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintDocumentAdapter.LayoutResultCallback;
+import android.print.PrintDocumentAdapter.WriteResultCallback;
+import android.print.PrintDocumentInfo;
+import android.print.PrinterCapabilitiesInfo;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import android.print.cts.services.FirstPrintService;
+import android.print.cts.services.PrintServiceCallbacks;
+import android.print.cts.services.PrinterDiscoverySessionCallbacks;
+import android.print.cts.services.SecondPrintService;
+import android.print.cts.services.StubbablePrinterDiscoverySession;
+import android.printservice.PrintJob;
+import android.printservice.PrintService;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiSelector;
+
+import org.mockito.InOrder;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This test verifies that the system correctly adjust the
+ * page ranges to be printed depending whether the app gave
+ * the requested pages, more pages, etc.
+ */
+public class PageRangeAdjustmentTest extends BasePrintTest {
+
+ private static final String FIRST_PRINTER = "First printer";
+
+ public void testAllPagesWantedAndAllPagesWritten() throws Exception {
+ // Create a callback for the target print service.
+ PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
+ new Answer<PrinterDiscoverySessionCallbacks>() {
+ @Override
+ public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+ return createMockFirstPrinterDiscoverySessionCallbacks();
+ }
+ },
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+ PageRange[] pages = printJob.getInfo().getPages();
+ assert(pages.length == 1 && PageRange.ALL_PAGES.equals(pages[0]));
+ printJob.complete();
+ onPrintJobQueuedCalled();
+ return null;
+ }
+ }, null);
+
+ // Configure the print services.
+ FirstPrintService.setCallbacks(firstServiceCallbacks);
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+ // Create a mock print adapter.
+ final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+ PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+ .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+ .setPageCount(3)
+ .build();
+ callback.onLayoutFinished(info, false);
+ // Mark layout was called.
+ onLayoutCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ PageRange[] pages = (PageRange[]) args[0];
+ ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+ WriteResultCallback callback = (WriteResultCallback) args[3];
+ fd.close();
+ callback.onWriteFinished(pages);
+ // Mark write was called.
+ onWriteCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Mark finish was called.
+ onFinishCalled();
+ return null;
+ }
+ });
+
+ // Start printing.
+ print(adapter);
+
+ // Wait for write.
+ waitForWriteForAdapterCallback();
+
+ // Select the first printer.
+ selectPrinter(FIRST_PRINTER);
+
+ // Wait for layout as the printer has different capabilities.
+ waitForLayoutAdapterCallbackCount(2);
+
+ // Click the print button.
+ clickPrintButton();
+
+ // Wait for finish.
+ waitForAdapterCallbackFinish();
+
+ // Wait for the print job.
+ waitForServiceOnPrintJobQueuedCallbackCalled();
+
+ // Verify the expected calls.
+ InOrder inOrder = inOrder(firstServiceCallbacks);
+
+ // We create a new session first.
+ inOrder.verify(firstServiceCallbacks)
+ .onCreatePrinterDiscoverySessionCallbacks();
+
+ // Next we wait for a call with the print job.
+ inOrder.verify(firstServiceCallbacks).onPrintJobQueued(
+ any(PrintJob.class));
+ }
+
+ public void testSomePagesWantedAndAllPagesWritten() throws Exception {
+ // Create a callback for the target print service.
+ PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
+ new Answer<PrinterDiscoverySessionCallbacks>() {
+ @Override
+ public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+ return createMockFirstPrinterDiscoverySessionCallbacks();
+ }
+ },
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+ PageRange[] pages = printJob.getInfo().getPages();
+ // We always as for the first page for preview and in this
+ // case we write all, i.e. more that needed.
+ assertTrue(pages.length == 1 && pages[0].getStart() == 1
+ && pages[0].getEnd() == 1);
+ printJob.complete();
+ onPrintJobQueuedCalled();
+ return null;
+ }
+ }, null);
+
+ // Configure the print services.
+ FirstPrintService.setCallbacks(firstServiceCallbacks);
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+ // Create a mock print adapter.
+ final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+ PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+ .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+ .setPageCount(3)
+ .build();
+ callback.onLayoutFinished(info, false);
+ // Mark layout was called.
+ onLayoutCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+ WriteResultCallback callback = (WriteResultCallback) args[3];
+ fd.close();
+ callback.onWriteFinished(new PageRange[] {PageRange.ALL_PAGES});
+ // Mark write was called.
+ onWriteCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Mark finish was called.
+ onFinishCalled();
+ return null;
+ }
+ });
+
+ // Start printing.
+ print(adapter);
+
+ // Wait for write.
+ waitForWriteForAdapterCallback();
+
+ // Select the first printer.
+ selectPrinter(FIRST_PRINTER);
+
+ // Wait for layout as the printer has different capabilities.
+ waitForLayoutAdapterCallbackCount(2);
+
+ // Select only the second page.
+ selectPages("2");
+
+ // Click the print button.
+ clickPrintButton();
+
+ // Wait for finish.
+ waitForAdapterCallbackFinish();
+
+ // Wait for the print job.
+ waitForServiceOnPrintJobQueuedCallbackCalled();
+
+ // Verify the expected calls.
+ InOrder inOrder = inOrder(firstServiceCallbacks);
+
+ // We create a new session first.
+ inOrder.verify(firstServiceCallbacks)
+ .onCreatePrinterDiscoverySessionCallbacks();
+
+ // Next we wait for a call with the print job.
+ inOrder.verify(firstServiceCallbacks).onPrintJobQueued(
+ any(PrintJob.class));
+ }
+
+ public void testSomePagesWantedAndSomeMorePagesWritten() throws Exception {
+ // Create a callback for the target print service.
+ PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
+ new Answer<PrinterDiscoverySessionCallbacks>() {
+ @Override
+ public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+ return createMockFirstPrinterDiscoverySessionCallbacks();
+ }
+ },
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+ PageRange[] pages = printJob.getInfo().getPages();
+ assert(pages.length == 1 && pages[0].getStart() == 1
+ && pages[0].getEnd() == 2);
+ printJob.complete();
+ onPrintJobQueuedCalled();
+ return null;
+ }
+ }, null);
+
+ // Configure the print services.
+ FirstPrintService.setCallbacks(firstServiceCallbacks);
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+ // Create a mock print adapter.
+ final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+ PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+ .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+ .setPageCount(3)
+ .build();
+ callback.onLayoutFinished(info, false);
+ // Mark layout was called.
+ onLayoutCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ PageRange[] pages = (PageRange[]) args[0];
+ ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+ WriteResultCallback callback = (WriteResultCallback) args[3];
+ // We expect a single range as it is either the first page
+ // or the page we selected in the UI.
+ assertSame(pages.length, 1);
+ fd.close();
+
+ PageRange reqeustedPages = pages[0];
+ if (reqeustedPages.getStart() == reqeustedPages.getEnd()
+ && reqeustedPages.getEnd() == 0) {
+ // If asked for the first page, which is for preview
+ // then write it...
+ callback.onWriteFinished(pages);
+ } else {
+ // otherwise write a page more that the one we selected.
+ callback.onWriteFinished(new PageRange[] {new PageRange(2, 3)});
+ }
+ // Mark write was called.
+ onWriteCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Mark finish was called.
+ onFinishCalled();
+ return null;
+ }
+ });
+
+ // Start printing.
+ print(adapter);
+
+ // Wait for write.
+ waitForWriteForAdapterCallback();
+
+ // Select the first printer.
+ selectPrinter(FIRST_PRINTER);
+
+ // Wait for layout as the printer has different capabilities.
+ waitForLayoutAdapterCallbackCount(2);
+
+ // Select only the third page.
+ selectPages("3");
+
+ // Click the print button.
+ clickPrintButton();
+
+ // Wait for finish.
+ waitForAdapterCallbackFinish();
+
+ // Wait for the print job.
+ waitForServiceOnPrintJobQueuedCallbackCalled();
+
+ // Verify the expected calls.
+ InOrder inOrder = inOrder(firstServiceCallbacks);
+
+ // We create a new session first.
+ inOrder.verify(firstServiceCallbacks)
+ .onCreatePrinterDiscoverySessionCallbacks();
+
+ // Next we wait for a call with the print job.
+ inOrder.verify(firstServiceCallbacks).onPrintJobQueued(
+ any(PrintJob.class));
+ }
+
+ public void testSomePagesWantedAndNotWritten() throws Exception {
+ // Create a callback for the target print service.
+ PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
+ new Answer<PrinterDiscoverySessionCallbacks>() {
+ @Override
+ public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+ return createMockFirstPrinterDiscoverySessionCallbacks();
+ }
+ },
+ null, null);
+
+ // Configure the print services.
+ FirstPrintService.setCallbacks(firstServiceCallbacks);
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+ // Create a mock print adapter.
+ final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+ PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+ .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+ .setPageCount(3)
+ .build();
+ callback.onLayoutFinished(info, false);
+ // Mark layout was called.
+ onLayoutCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ PageRange[] pages = (PageRange[]) args[0];
+ ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+ WriteResultCallback callback = (WriteResultCallback) args[3];
+ assertSame(pages.length, 1);
+ fd.close();
+
+ // We should be asked for the first page...
+ assertSame(pages[0].getStart(), 0);
+ assertSame(pages[0].getEnd(), 0);
+
+ // ...just write a the wring page.
+ callback.onWriteFinished(new PageRange[] {new PageRange(1, 1)});
+
+ // Mark write was called.
+ onWriteCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Mark finish was called.
+ onFinishCalled();
+ return null;
+ }
+ });
+
+ // Start printing.
+ print(adapter);
+
+ // Wait for write.
+ waitForWriteForAdapterCallback();
+
+ // Cancel printing.
+ UiDevice.getInstance().pressBack(); // wakes up the device.
+ UiDevice.getInstance().pressBack();
+
+ // Wait for finish.
+ waitForAdapterCallbackFinish();
+
+ // Verify the expected calls.
+ InOrder inOrder = inOrder(firstServiceCallbacks);
+
+ // We create a new session first.
+ inOrder.verify(firstServiceCallbacks)
+ .onCreatePrinterDiscoverySessionCallbacks();
+
+ // We should not receive a print job callback.
+ inOrder.verify(firstServiceCallbacks, never()).onPrintJobQueued(
+ any(PrintJob.class));
+ }
+
+ private void selectPages(String pages) throws UiObjectNotFoundException {
+ UiObject pagesSpinner = new UiObject(new UiSelector().resourceId(
+ "com.android.printspooler:id/range_options_spinner"));
+ pagesSpinner.click();
+
+ UiObject rangeOption = new UiObject(new UiSelector().text("Range"));
+ rangeOption.click();
+
+ UiObject pagesEditText = new UiObject(new UiSelector().resourceId(
+ "com.android.printspooler:id/page_range_edittext"));
+ pagesEditText.setText(pages);
+ }
+
+ private PrinterDiscoverySessionCallbacks createMockFirstPrinterDiscoverySessionCallbacks() {
+ return createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ PrinterDiscoverySessionCallbacks mock = (PrinterDiscoverySessionCallbacks)
+ invocation.getMock();
+
+ StubbablePrinterDiscoverySession session = mock.getSession();
+ PrintService service = session.getService();
+
+ if (session.getPrinters().isEmpty()) {
+ List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
+
+ // Add one printer.
+ PrinterId firstPrinterId = service.generatePrinterId("first_printer");
+ PrinterCapabilitiesInfo firstCapabilities =
+ new PrinterCapabilitiesInfo.Builder(firstPrinterId)
+ .setMinMargins(new Margins(200, 200, 200, 200))
+ .addMediaSize(MediaSize.ISO_A4, true)
+ .addMediaSize(MediaSize.ISO_A5, false)
+ .addResolution(new Resolution("300x300", "300x300", 300, 300), true)
+ .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+ PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ PrinterInfo firstPrinter = new PrinterInfo.Builder(firstPrinterId,
+ "First printer", PrinterInfo.STATUS_IDLE)
+ .setCapabilities(firstCapabilities)
+ .build();
+ printers.add(firstPrinter);
+
+ session.addPrinters(printers);
+ }
+
+ return null;
+ }
+ }, null, null, null, null, null);
+ }
+
+ private PrintServiceCallbacks createSecondMockPrintServiceCallbacks() {
+ return createMockPrintServiceCallbacks(null, null, null);
+ }
+}
diff --git a/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractActivity.java b/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractActivity.java
new file mode 100644
index 0000000..eb80bb7
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractActivity.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class PrintDocumentAdapterContractActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+}
diff --git a/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java b/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
new file mode 100644
index 0000000..64c225a
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
@@ -0,0 +1,1482 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.cts;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.os.CancellationSignal;
+import android.os.CancellationSignal.OnCancelListener;
+import android.os.ParcelFileDescriptor;
+import android.print.PageRange;
+import android.print.PrintAttributes;
+import android.print.PrintAttributes.Margins;
+import android.print.PrintAttributes.MediaSize;
+import android.print.PrintAttributes.Resolution;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintDocumentAdapter.LayoutResultCallback;
+import android.print.PrintDocumentAdapter.WriteResultCallback;
+import android.print.PrintDocumentInfo;
+import android.print.PrinterCapabilitiesInfo;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import android.print.cts.services.FirstPrintService;
+import android.print.cts.services.PrintServiceCallbacks;
+import android.print.cts.services.PrinterDiscoverySessionCallbacks;
+import android.print.cts.services.SecondPrintService;
+import android.print.cts.services.StubbablePrinterDiscoverySession;
+import android.printservice.PrintJob;
+import android.printservice.PrintService;
+import android.support.test.uiautomator.UiDevice;
+
+import org.mockito.InOrder;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This test verifies that the system respects the {@link PrintDocumentAdapter}
+ * contract and invokes all callbacks as expected.
+ */
+public class PrintDocumentAdapterContractTest extends BasePrintTest {
+
+ public void testNoPrintOptionsOrPrinterChange() throws Exception {
+ // Configure the print services.
+ FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+ // Create a mock print adapter.
+ final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+ PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+ .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).setPageCount(1)
+ .build();
+ callback.onLayoutFinished(info, false);
+ // Mark layout was called.
+ onLayoutCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ PageRange[] pages = (PageRange[]) args[0];
+ ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+ WriteResultCallback callback = (WriteResultCallback) args[3];
+ fd.close();
+ callback.onWriteFinished(pages);
+ // Mark write was called.
+ onWriteCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Mark finish was called.
+ onFinishCalled();
+ return null;
+ }
+ });
+
+ // Start printing.
+ print(adapter);
+
+ // Wait for write.
+ waitForWriteForAdapterCallback();
+
+ // Select the second printer.
+ selectPrinter("Second printer");
+
+ // Wait for layout.
+ waitForLayoutAdapterCallbackCount(2);
+
+ // Click the print button.
+ clickPrintButton();
+
+ // Wait for finish.
+ waitForAdapterCallbackFinish();
+
+ // Verify the expected calls.
+ InOrder inOrder = inOrder(adapter);
+
+ // Start is always called first.
+ inOrder.verify(adapter).onStart();
+
+ // Start is always followed by a layout. The PDF printer is selected if
+ // there are other printers but none of them was used.
+ PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
+ PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.NA_LETTER)
+ .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
+ .setMinMargins(Margins.NO_MARGINS)
+ .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
+
+ // We always ask for the first page for preview.
+ PageRange[] firstPages = new PageRange[] {new PageRange(0, 0)};
+ inOrder.verify(adapter).onWrite(eq(firstPages), any(ParcelFileDescriptor.class),
+ any(CancellationSignal.class), any(WriteResultCallback.class));
+
+ // We selected the second printer which does not support the media
+ // size that was selected, so a new layout happens as the size changed.
+ // Since we passed false to the layout callback meaning that the content
+ // didn't change, there shouldn't be a next call to write.
+ PrintAttributes secondOldAttributes = firstNewAttributes;
+ PrintAttributes secondNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.ISO_A3)
+ .setResolution(new Resolution("300x300", "300x300", 300, 300))
+ .setMinMargins(Margins.NO_MARGINS)
+ .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, secondOldAttributes, secondNewAttributes, true);
+
+ // When print is pressed we ask for a layout which is *not* for preview.
+ verifyLayoutCall(inOrder, adapter, secondNewAttributes, secondNewAttributes, false);
+
+ // When print is pressed we ask for all selected pages.
+ PageRange[] secondPages = new PageRange[] {PageRange.ALL_PAGES};
+ inOrder.verify(adapter).onWrite(eq(secondPages), any(ParcelFileDescriptor.class),
+ any(CancellationSignal.class), any(WriteResultCallback.class));
+
+ // Finish is always called last.
+ inOrder.verify(adapter).onFinish();
+
+ // No other call are expected.
+ verifyNoMoreInteractions(adapter);
+ }
+
+ public void testNoPrintOptionsOrPrinterChangeCanceled() throws Exception {
+ // Configure the print services.
+ FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+ // Create a mock print adapter.
+ final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ LayoutResultCallback callback = (LayoutResultCallback)
+ invocation.getArguments()[3];
+ PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+ .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+ .setPageCount(1)
+ .build();
+ callback.onLayoutFinished(info, false);
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ PageRange[] pages = (PageRange[]) args[0];
+ ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+ WriteResultCallback callback = (WriteResultCallback) args[3];
+ fd.close();
+ callback.onWriteFinished(pages);
+ // Mark write was called.
+ onWriteCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Mark finish was called.
+ onFinishCalled();
+ return null;
+ }
+ });
+
+ // Start printing.
+ print(adapter);
+
+ // Wait for write.
+ waitForWriteForAdapterCallback();
+
+ // Cancel the printing.
+ UiDevice.getInstance().pressBack(); // wakes up the device.
+ UiDevice.getInstance().pressBack();
+
+ // Wait for finish.
+ waitForAdapterCallbackFinish();
+
+ // Verify the expected calls.
+ InOrder inOrder = inOrder(adapter);
+
+ // Start is always called first.
+ inOrder.verify(adapter).onStart();
+
+ // Start is always followed by a layout. The PDF printer is selected if
+ // there are other printers but none of them was used.
+ PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
+ PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.NA_LETTER)
+ .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
+ .setMinMargins(Margins.NO_MARGINS)
+ .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
+
+ // We always ask for the first page for preview.
+ PageRange[] firstPages = new PageRange[] {new PageRange(0, 0)};
+ inOrder.verify(adapter).onWrite(eq(firstPages), any(ParcelFileDescriptor.class),
+ any(CancellationSignal.class), any(WriteResultCallback.class));
+
+ // Finish is always called last.
+ inOrder.verify(adapter).onFinish();
+
+ // No other call are expected.
+ verifyNoMoreInteractions(adapter);
+ }
+
+ public void testPrintOptionsChangeAndNoPrinterChange() throws Exception {
+ // Configure the print services.
+ FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+ // Create a mock print adapter.
+ final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ LayoutResultCallback callback = (LayoutResultCallback)
+ invocation.getArguments()[3];
+ PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+ .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+ .setPageCount(1)
+ .build();
+ callback.onLayoutFinished(info, false);
+ // Mark layout was called.
+ onLayoutCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ PageRange[] pages = (PageRange[]) args[0];
+ ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+ WriteResultCallback callback = (WriteResultCallback) args[3];
+ fd.close();
+ callback.onWriteFinished(pages);
+ // Mark write was called.
+ onWriteCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Mark finish was called.
+ onFinishCalled();
+ return null;
+ }
+ });
+
+ // Start printing.
+ print(adapter);
+
+ // Wait for write.
+ waitForWriteForAdapterCallback();
+
+ // Select the second printer.
+ selectPrinter("Second printer");
+
+ // Wait for layout.
+ waitForLayoutAdapterCallbackCount(2);
+
+ // Change the orientation.
+ changeOrientation("Landscape");
+
+ // Wait for layout.
+ waitForLayoutAdapterCallbackCount(3);
+
+ // Change the media size.
+ changeMediaSize("ISO A4");
+
+ // Wait for layout.
+ waitForLayoutAdapterCallbackCount(4);
+
+ // Change the color.
+ changeColor("Black & White");
+
+ // Wait for layout.
+ waitForLayoutAdapterCallbackCount(5);
+
+ // Click the print button.
+ clickPrintButton();
+
+ // Wait for a finish.
+ waitForAdapterCallbackFinish();
+
+ // Verify the expected calls.
+ InOrder inOrder = inOrder(adapter);
+
+ // Start is always called first.
+ inOrder.verify(adapter).onStart();
+
+ // Start is always followed by a layout. The PDF printer is selected if
+ // there are other printers but none of them was used.
+ PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
+ PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.NA_LETTER)
+ .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
+ .setMinMargins(Margins.NO_MARGINS)
+ .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
+
+ // We always ask for the first page for preview.
+ PageRange[] firstPages = new PageRange[] {new PageRange(0, 0)};
+ inOrder.verify(adapter).onWrite(eq(firstPages), any(ParcelFileDescriptor.class),
+ any(CancellationSignal.class), any(WriteResultCallback.class));
+
+ // We selected the second printer which does not support the media
+ // size that was selected, so a new layout happens as the size changed.
+ // Since we passed false to the layout callback meaning that the content
+ // didn't change, there shouldn't be a next call to write.
+ PrintAttributes secondOldAttributes = firstNewAttributes;
+ PrintAttributes secondNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.ISO_A3)
+ .setResolution(new Resolution("300x300", "300x300", 300, 300))
+ .setMinMargins(Margins.NO_MARGINS)
+ .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, secondOldAttributes, secondNewAttributes, true);
+
+ // We changed the orientation which triggers a layout. Since we passed
+ // false to the layout callback meaning that the content didn't change,
+ // there shouldn't be a next call to write.
+ PrintAttributes thirdOldAttributes = secondNewAttributes;
+ PrintAttributes thirdNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.ISO_A3.asLandscape())
+ .setResolution(new Resolution("300x300", "300x300", 300, 300))
+ .setMinMargins(Margins.NO_MARGINS)
+ .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, thirdOldAttributes, thirdNewAttributes, true);
+
+ // We changed the media size which triggers a layout. Since we passed
+ // false to the layout callback meaning that the content didn't change,
+ // there shouldn't be a next call to write.
+ PrintAttributes fourthOldAttributes = thirdNewAttributes;
+ PrintAttributes fourthNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.ISO_A4.asLandscape())
+ .setResolution(new Resolution("300x300", "300x300", 300, 300))
+ .setMinMargins(Margins.NO_MARGINS)
+ .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, fourthOldAttributes, fourthNewAttributes, true);
+
+ // We changed the color which triggers a layout. Since we passed
+ // false to the layout callback meaning that the content didn't change,
+ // there shouldn't be a next call to write.
+ PrintAttributes fifthOldAttributes = fourthNewAttributes;
+ PrintAttributes fifthNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.ISO_A4.asLandscape())
+ .setResolution(new Resolution("300x300", "300x300", 300, 300))
+ .setMinMargins(Margins.NO_MARGINS)
+ .setColorMode(PrintAttributes.COLOR_MODE_MONOCHROME)
+ .build();
+ verifyLayoutCall(inOrder, adapter, fifthOldAttributes, fifthNewAttributes, true);
+
+ // When print is pressed we ask for a layout which is *not* for preview.
+ verifyLayoutCall(inOrder, adapter, fifthNewAttributes, fifthNewAttributes, false);
+
+ // When print is pressed we ask for all selected pages.
+ PageRange[] secondPages = new PageRange[] {PageRange.ALL_PAGES};
+ inOrder.verify(adapter).onWrite(eq(secondPages), any(ParcelFileDescriptor.class),
+ any(CancellationSignal.class), any(WriteResultCallback.class));
+
+ // Finish is always called last.
+ inOrder.verify(adapter).onFinish();
+
+ // No other call are expected.
+ verifyNoMoreInteractions(adapter);
+ }
+
+ public void testPrintOptionsChangeAndPrinterChange() throws Exception {
+ // Configure the print services.
+ FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+ // Create a mock print adapter.
+ final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ LayoutResultCallback callback = (LayoutResultCallback)
+ invocation.getArguments()[3];
+ PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+ .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+ .setPageCount(1)
+ .build();
+ callback.onLayoutFinished(info, false);
+ // Mark layout was called.
+ onLayoutCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ PageRange[] pages = (PageRange[]) args[0];
+ ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+ WriteResultCallback callback = (WriteResultCallback) args[3];
+ fd.close();
+ callback.onWriteFinished(pages);
+ // Mark write was called.
+ onWriteCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Mark finish was called.
+ onFinishCalled();
+ return null;
+ }
+ });
+
+ // Start printing.
+ print(adapter);
+
+ // Wait for write.
+ waitForWriteForAdapterCallback();
+
+ // Select the second printer.
+ selectPrinter("Second printer");
+
+ // Wait for layout.
+ waitForLayoutAdapterCallbackCount(2);
+
+ // Change the color.
+ changeColor("Black & White");
+
+ // Wait for layout.
+ waitForLayoutAdapterCallbackCount(3);
+
+ // Change the printer to one which supports the current media size.
+ // Select the second printer.
+ selectPrinter("First printer");
+
+ // Wait for layout.
+ waitForLayoutAdapterCallbackCount(4);
+
+ // Click the print button.
+ clickPrintButton();
+
+ // Wait for a finish.
+ waitForAdapterCallbackFinish();
+
+ // Verify the expected calls.
+ InOrder inOrder = inOrder(adapter);
+
+ // Start is always called first.
+ inOrder.verify(adapter).onStart();
+
+ // Start is always followed by a layout. The PDF printer is selected if
+ // there are other printers but none of them was used.
+ PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
+ PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.NA_LETTER)
+ .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
+ .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
+
+ // We always ask for the first page for preview.
+ PageRange[] firstPages = new PageRange[] {new PageRange(0, 0)};
+ inOrder.verify(adapter).onWrite(eq(firstPages), any(ParcelFileDescriptor.class),
+ any(CancellationSignal.class), any(WriteResultCallback.class));
+
+ // We changed the printer and the new printer does not support the
+ // selected media size in which case the default media size of the
+ // printer is used resulting in a layout pass. Same for margins.
+ PrintAttributes secondOldAttributes = firstNewAttributes;
+ PrintAttributes secondNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.ISO_A3)
+ .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
+ .setMinMargins(new Margins(0, 0, 0, 0))
+ .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, secondOldAttributes, secondNewAttributes, true);
+
+ // We changed the printer and the new printer does not support the
+ // current color in which case the default color for the selected
+ // printer is used resulting in a layout pass.
+ PrintAttributes thirdOldAttributes = secondNewAttributes;
+ PrintAttributes thirdNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.ISO_A3)
+ .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
+ .setMinMargins(new Margins(0, 0, 0, 0))
+ .setColorMode(PrintAttributes.COLOR_MODE_MONOCHROME)
+ .build();
+ verifyLayoutCall(inOrder, adapter, thirdOldAttributes, thirdNewAttributes, true);
+
+ // We changed the printer to one that does not support the current
+ // media size in which case we pick the default media size for the
+ // new printer which results in a layout pass. Same for color.
+ PrintAttributes fourthOldAttributes = thirdNewAttributes;
+ PrintAttributes fourthNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.ISO_A4)
+ .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
+ .setMinMargins(new Margins(200, 200, 200, 200))
+ .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, fourthOldAttributes, fourthNewAttributes, true);
+
+ // When print is pressed we ask for a layout which is *not* for preview.
+ verifyLayoutCall(inOrder, adapter, fourthNewAttributes, fourthNewAttributes, false);
+
+ // When print is pressed we ask for all selected pages.
+ PageRange[] secondPages = new PageRange[] {PageRange.ALL_PAGES};
+ inOrder.verify(adapter).onWrite(eq(secondPages), any(ParcelFileDescriptor.class),
+ any(CancellationSignal.class), any(WriteResultCallback.class));
+
+ // Finish is always called last.
+ inOrder.verify(adapter).onFinish();
+
+ // No other call are expected.
+ verifyNoMoreInteractions(adapter);
+ }
+
+ public void testPrintOptionsChangeAndNoPrinterChangeAndContentChange()
+ throws Exception {
+ // Configure the print services.
+ FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+ // Create a mock print adapter.
+ final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+ PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+ .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).setPageCount(1)
+ .build();
+ // The content changes after every layout.
+ callback.onLayoutFinished(info, true);
+ // Mark layout was called.
+ onLayoutCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ PageRange[] pages = (PageRange[]) args[0];
+ ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+ WriteResultCallback callback = (WriteResultCallback) args[3];
+ fd.close();
+ callback.onWriteFinished(pages);
+ // Mark write was called.
+ onWriteCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Mark finish was called.
+ onFinishCalled();
+ return null;
+ }
+ });
+
+ // Start printing.
+ print(adapter);
+
+ // Wait for write.
+ waitForWriteForAdapterCallback();
+
+ // Select the second printer.
+ selectPrinter("Second printer");
+
+ // Wait for layout.
+ waitForLayoutAdapterCallbackCount(2);
+
+ // Click the print button.
+ clickPrintButton();
+
+ // Wait for a finish.
+ waitForAdapterCallbackFinish();
+
+ // Verify the expected calls.
+ InOrder inOrder = inOrder(adapter);
+
+ // Start is always called first.
+ inOrder.verify(adapter).onStart();
+
+ // Start is always followed by a layout. The PDF printer is selected if
+ // there are other printers but none of them was used.
+ PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
+ PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.NA_LETTER)
+ .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
+ .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
+
+ // We always ask for the first page for preview.
+ PageRange[] firstPages = new PageRange[] {new PageRange(0, 0)};
+ inOrder.verify(adapter).onWrite(eq(firstPages), any(ParcelFileDescriptor.class),
+ any(CancellationSignal.class), any(WriteResultCallback.class));
+
+ // We selected the second printer which does not support the media
+ // size that was selected, so a new layout happens as the size changed.
+ PrintAttributes secondOldAttributes = firstNewAttributes;
+ PrintAttributes secondNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.ISO_A3)
+ .setResolution(new Resolution("300x300", "300x300", 300, 300))
+ .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, secondOldAttributes, secondNewAttributes, true);
+
+ // In the layout callback we reported that the content changed,
+ // so the previously written page has to be written again.
+ PageRange[] secondPages = new PageRange[] {new PageRange(0, 0)};
+ inOrder.verify(adapter).onWrite(eq(secondPages), any(ParcelFileDescriptor.class),
+ any(CancellationSignal.class), any(WriteResultCallback.class));
+
+ // When print is pressed we ask for a layout which is *not* for preview.
+ verifyLayoutCall(inOrder, adapter, secondNewAttributes, secondNewAttributes, false);
+
+ // When print is pressed we ask for all selected pages.
+ PageRange[] thirdPages = new PageRange[] {PageRange.ALL_PAGES};
+ inOrder.verify(adapter).onWrite(eq(thirdPages), any(ParcelFileDescriptor.class),
+ any(CancellationSignal.class), any(WriteResultCallback.class));
+
+ // Finish is always called last.
+ inOrder.verify(adapter).onFinish();
+
+ // No other call are expected.
+ verifyNoMoreInteractions(adapter);
+ }
+
+ public void testNewPrinterSupportsSelectedPrintOptions() throws Exception {
+ // Configure the print services.
+ FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+ // Create a mock print adapter.
+ final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+ PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+ .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).setPageCount(1)
+ .build();
+ // The content changes after every layout.
+ callback.onLayoutFinished(info, false);
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ PageRange[] pages = (PageRange[]) args[0];
+ ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+ WriteResultCallback callback = (WriteResultCallback) args[3];
+ fd.close();
+ callback.onWriteFinished(pages);
+ // Mark write was called.
+ onWriteCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Mark finish was called.
+ onFinishCalled();
+ return null;
+ }
+ });
+
+ // Start printing.
+ print(adapter);
+
+ // Wait for write.
+ waitForWriteForAdapterCallback();
+
+ // Select the third printer.
+ selectPrinter("Third printer");
+
+ // Click the print button.
+ clickPrintButton();
+
+ // Wait for a finish.
+ waitForAdapterCallbackFinish();
+
+ // Verify the expected calls.
+ InOrder inOrder = inOrder(adapter);
+
+ // Start is always called first.
+ inOrder.verify(adapter).onStart();
+
+ // Start is always followed by a layout. The PDF printer is selected if
+ // there are other printers but none of them was used.
+ PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
+ PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.NA_LETTER)
+ .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
+ .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
+
+ // We always ask for the first page for preview.
+ PageRange[] firstPages = new PageRange[] {new PageRange(0, 0)};
+ inOrder.verify(adapter).onWrite(eq(firstPages), any(ParcelFileDescriptor.class),
+ any(CancellationSignal.class), any(WriteResultCallback.class));
+
+ // When print is pressed we ask for a layout which is *not* for preview.
+ verifyLayoutCall(inOrder, adapter, firstNewAttributes, firstNewAttributes, false);
+
+ // When print is pressed we ask for all selected pages.
+ PageRange[] thirdPages = new PageRange[] {PageRange.ALL_PAGES};
+ inOrder.verify(adapter).onWrite(eq(thirdPages), any(ParcelFileDescriptor.class),
+ any(CancellationSignal.class), any(WriteResultCallback.class));
+
+ // Finish is always called last.
+ inOrder.verify(adapter).onFinish();
+
+ // No other call are expected.
+ verifyNoMoreInteractions(adapter);
+ }
+
+ public void testNothingChangesAllPagesWrittenFirstTime() throws Exception {
+ // Configure the print services.
+ FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+ // Create a mock print adapter.
+ final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+ PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+ .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).setPageCount(3)
+ .build();
+ callback.onLayoutFinished(info, false);
+ // Mark layout was called.
+ onLayoutCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+ WriteResultCallback callback = (WriteResultCallback) args[3];
+ fd.close();
+ callback.onWriteFinished(new PageRange[] {PageRange.ALL_PAGES});
+ // Mark write was called.
+ onWriteCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Mark finish was called.
+ onFinishCalled();
+ return null;
+ }
+ });
+
+ // Start printing.
+ print(adapter);
+
+ // Wait for write.
+ waitForWriteForAdapterCallback();
+
+ // Select the second printer.
+ selectPrinter("Second printer");
+
+ // Wait for layout.
+ waitForLayoutAdapterCallbackCount(2);
+
+ // Click the print button.
+ clickPrintButton();
+
+ // Wait for a finish.
+ waitForAdapterCallbackFinish();
+
+ // Verify the expected calls.
+ InOrder inOrder = inOrder(adapter);
+
+ // Start is always called first.
+ inOrder.verify(adapter).onStart();
+
+ // Start is always followed by a layout. The PDF printer is selected if
+ // there are other printers but none of them was used.
+ PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
+ PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.NA_LETTER)
+ .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
+ .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
+
+ // We always ask for the first page for preview.
+ PageRange[] firstPages = new PageRange[] {new PageRange(0, 0)};
+ inOrder.verify(adapter).onWrite(eq(firstPages), any(ParcelFileDescriptor.class),
+ any(CancellationSignal.class), any(WriteResultCallback.class));
+
+ // We selected the second printer which does not support the media
+ // size that was selected, so a new layout happens as the size changed.
+ PrintAttributes secondOldAttributes = firstNewAttributes;
+ PrintAttributes secondNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.ISO_A3)
+ .setResolution(new Resolution("300x300", "300x300", 300, 300))
+ .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, secondOldAttributes, secondNewAttributes, true);
+
+ // In the layout callback we reported that the content didn't change,
+ // and we wrote all pages in the write call while being asked only
+ // for the first page. Hence, all pages were written and they didn't
+ // change, therefore no subsequent write call should happen.
+
+ // When print is pressed we ask for a layout which is *not* for preview.
+ verifyLayoutCall(inOrder, adapter, secondNewAttributes, secondNewAttributes, false);
+
+ // In the layout callback we reported that the content didn't change,
+ // and we wrote all pages in the write call while being asked only
+ // for the first page. Hence, all pages were written and they didn't
+ // change, therefore no subsequent write call should happen.
+
+ // Finish is always called last.
+ inOrder.verify(adapter).onFinish();
+
+ // No other call are expected.
+ verifyNoMoreInteractions(adapter);
+ }
+
+ public void testCancelLongRunningLayout() throws Exception {
+ // Configure the print services.
+ FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+ // Create a mock print adapter.
+ final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ CancellationSignal cancellation = (CancellationSignal) invocation.getArguments()[2];
+ final LayoutResultCallback callback = (LayoutResultCallback) invocation
+ .getArguments()[3];
+ cancellation.setOnCancelListener(new OnCancelListener() {
+ @Override
+ public void onCancel() {
+ callback.onLayoutCancelled();
+ }
+ });
+ onLayoutCalled();
+ return null;
+ }
+ }, null, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Mark finish was called.
+ onFinishCalled();
+ return null;
+ }
+ });
+
+ // Start printing.
+ print(adapter);
+
+ // Wait for layout.
+ waitForLayoutAdapterCallbackCount(1);
+
+ // Cancel printing.
+ UiDevice.getInstance().pressBack(); // wakes up the device.
+ UiDevice.getInstance().pressBack();
+
+ // Wait for a finish.
+ waitForAdapterCallbackFinish();
+
+ // Verify the expected calls.
+ InOrder inOrder = inOrder(adapter);
+
+ // Start is always called first.
+ inOrder.verify(adapter).onStart();
+
+ // Start is always followed by a layout. The PDF printer is selected if
+ // there are other printers but none of them was used.
+ PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
+ PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.NA_LETTER)
+ .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
+ .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
+
+ // Finish is always called last.
+ inOrder.verify(adapter).onFinish();
+
+ // No other call are expected.
+ verifyNoMoreInteractions(adapter);
+ }
+
+ public void testCancelLongRunningWrite() throws Exception {
+ // Configure the print services.
+ FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+ // Create a mock print adapter.
+ final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+ PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+ .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).setPageCount(1)
+ .build();
+ callback.onLayoutFinished(info, false);
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ final ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+ final CancellationSignal cancellation = (CancellationSignal) args[2];
+ final WriteResultCallback callback = (WriteResultCallback) args[3];
+ cancellation.setOnCancelListener(new OnCancelListener() {
+ @Override
+ public void onCancel() {
+ try {
+ fd.close();
+ } catch (IOException ioe) {
+ /* ignore */
+ }
+ callback.onWriteCancelled();
+ }
+ });
+ // Mark write was called.
+ onWriteCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Mark finish was called.
+ onFinishCalled();
+ return null;
+ }
+ });
+
+ // Start printing.
+ print(adapter);
+
+ // Wait for write.
+ waitForWriteForAdapterCallback();
+
+ // Cancel printing.
+ UiDevice.getInstance().pressBack(); // wakes up the device.
+ UiDevice.getInstance().pressBack();
+
+ // Wait for a finish.
+ waitForAdapterCallbackFinish();
+
+ // Verify the expected calls.
+ InOrder inOrder = inOrder(adapter);
+
+ // Start is always called first.
+ inOrder.verify(adapter).onStart();
+
+ // Start is always followed by a layout. The PDF printer is selected if
+ // there are other printers but none of them was used.
+ PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
+ PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.NA_LETTER)
+ .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
+ .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
+
+ // We always ask for the first page for preview.
+ PageRange[] firstPages = new PageRange[] {new PageRange(0, 0)};
+ inOrder.verify(adapter).onWrite(eq(firstPages), any(ParcelFileDescriptor.class),
+ any(CancellationSignal.class), any(WriteResultCallback.class));
+
+ // Finish is always called last.
+ inOrder.verify(adapter).onFinish();
+
+ // No other call are expected.
+ verifyNoMoreInteractions(adapter);
+ }
+
+ public void testFailedLayout() throws Exception {
+ // Configure the print services.
+ FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+ // Create a mock print adapter.
+ final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+ callback.onLayoutFailed(null);
+ // Mark layout was called.
+ onLayoutCalled();
+ return null;
+ }
+ }, null, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Mark finish was called.
+ onFinishCalled();
+ return null;
+ }
+ });
+
+ // Start printing.
+ print(adapter);
+
+ // Wait for layout.
+ waitForLayoutAdapterCallbackCount(1);
+
+ // Cancel printing.
+ UiDevice.getInstance().pressBack(); // wakes up the device.
+ UiDevice.getInstance().pressBack();
+
+ // Wait for a finish.
+ waitForAdapterCallbackFinish();
+
+ // Verify the expected calls.
+ InOrder inOrder = inOrder(adapter);
+
+ // Start is always called first.
+ inOrder.verify(adapter).onStart();
+
+ // Start is always followed by a layout. The PDF printer is selected if
+ // there are other printers but none of them was used.
+ PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
+ PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.NA_LETTER)
+ .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
+ .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
+
+ // No write as layout failed.
+
+ // Finish is always called last.
+ inOrder.verify(adapter).onFinish();
+
+ // No other call are expected.
+ verifyNoMoreInteractions(adapter);
+ }
+
+ public void testFailedWrite() throws Exception {
+ // Configure the print services.
+ FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+ // Create a mock print adapter.
+ final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+ PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+ .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).setPageCount(1)
+ .build();
+ callback.onLayoutFinished(info, false);
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+ WriteResultCallback callback = (WriteResultCallback) args[3];
+ fd.close();
+ callback.onWriteFailed(null);
+ // Mark write was called.
+ onWriteCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Mark finish was called.
+ onFinishCalled();
+ return null;
+ }
+ });
+
+ // Start printing.
+ print(adapter);
+
+ // Wait for write.
+ waitForWriteForAdapterCallback();
+
+ // Cancel printing.
+ UiDevice.getInstance().pressBack(); // wakes up the device.
+ UiDevice.getInstance().pressBack();
+
+ // Wait for a finish.
+ waitForAdapterCallbackFinish();
+
+ // Verify the expected calls.
+ InOrder inOrder = inOrder(adapter);
+
+ // Start is always called first.
+ inOrder.verify(adapter).onStart();
+
+ // Start is always followed by a layout. The PDF printer is selected if
+ // there are other printers but none of them was used.
+ PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
+ PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.NA_LETTER)
+ .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
+ .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
+
+ // We always ask for the first page for preview.
+ PageRange[] firstPages = new PageRange[] {new PageRange(0, 0)};
+ inOrder.verify(adapter).onWrite(eq(firstPages), any(ParcelFileDescriptor.class),
+ any(CancellationSignal.class), any(WriteResultCallback.class));
+
+ // Finish is always called last.
+ inOrder.verify(adapter).onFinish();
+
+ // No other call are expected.
+ verifyNoMoreInteractions(adapter);
+ }
+
+ public void testRequestedPagesNotWritten() throws Exception {
+ // Configure the print services.
+ FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+ // Create a mock print adapter.
+ final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+ PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+ .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).setPageCount(1)
+ .build();
+ callback.onLayoutFinished(info, false);
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+ WriteResultCallback callback = (WriteResultCallback) args[3];
+ fd.close();
+ // Write wrong pages.
+ callback.onWriteFinished(new PageRange[] {
+ new PageRange(Integer.MAX_VALUE,Integer.MAX_VALUE)});
+ // Mark write was called.
+ onWriteCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Mark finish was called.
+ onFinishCalled();
+ return null;
+ }
+ });
+
+ // Start printing.
+ print(adapter);
+
+ // Wait for write.
+ waitForWriteForAdapterCallback();
+
+ // Cancel printing.
+ UiDevice.getInstance().pressBack(); // wakes up the device.
+ UiDevice.getInstance().pressBack();
+
+ // Wait for a finish.
+ waitForAdapterCallbackFinish();
+
+ // Verify the expected calls.
+ InOrder inOrder = inOrder(adapter);
+
+ // Start is always called first.
+ inOrder.verify(adapter).onStart();
+
+ // Start is always followed by a layout. The PDF printer is selected if
+ // there are other printers but none of them was used.
+ PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
+ PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.NA_LETTER)
+ .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
+ .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
+
+ // We always ask for the first page for preview.
+ PageRange[] firstPages = new PageRange[] {new PageRange(0, 0)};
+ inOrder.verify(adapter).onWrite(eq(firstPages), any(ParcelFileDescriptor.class),
+ any(CancellationSignal.class), any(WriteResultCallback.class));
+
+ // Finish is always called last.
+ inOrder.verify(adapter).onFinish();
+
+ // No other call are expected.
+ verifyNoMoreInteractions(adapter);
+ }
+
+ public void testLayoutCallbackNotCalled() throws Exception {
+ // Configure the print services.
+ FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+ // Create a mock print adapter.
+ final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Break the contract and never call the callback.
+ // Mark layout called.
+ onLayoutCalled();
+ return null;
+ }
+ }, null, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Mark finish was called.
+ onFinishCalled();
+ return null;
+ }
+ });
+
+ // Start printing.
+ print(adapter);
+
+ // Wait for layout.
+ waitForLayoutAdapterCallbackCount(1);
+
+ // Cancel printing.
+ UiDevice.getInstance().pressBack(); // wakes up the device.
+ UiDevice.getInstance().pressBack();
+
+ // Wait for a finish.
+ waitForAdapterCallbackFinish();
+
+ // Verify the expected calls.
+ InOrder inOrder = inOrder(adapter);
+
+ // Start is always called first.
+ inOrder.verify(adapter).onStart();
+
+ // Start is always followed by a layout. The PDF printer is selected if
+ // there are other printers but none of them was used.
+ PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
+ PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.NA_LETTER)
+ .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
+ .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
+
+ // Finish is always called last.
+ inOrder.verify(adapter).onFinish();
+
+ // No other call are expected.
+ verifyNoMoreInteractions(adapter);
+ }
+
+ public void testWriteCallbackNotCalled() throws Exception {
+ // Configure the print services.
+ FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+ // Create a mock print adapter.
+ final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+ PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+ .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).setPageCount(1)
+ .build();
+ callback.onLayoutFinished(info, false);
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+ fd.close();
+ // Break the contract and never call the callback.
+ // Mark write was called.
+ onWriteCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Mark finish was called.
+ onFinishCalled();
+ return null;
+ }
+ });
+
+ // Start printing.
+ print(adapter);
+
+ // Wait for write.
+ waitForWriteForAdapterCallback();
+
+ // Cancel printing.
+ UiDevice.getInstance().pressBack(); // wakes up the device.
+ UiDevice.getInstance().pressBack();
+
+ // Wait for a finish.
+ waitForAdapterCallbackFinish();
+
+ // Verify the expected calls.
+ InOrder inOrder = inOrder(adapter);
+
+ // Start is always called first.
+ inOrder.verify(adapter).onStart();
+
+ // Start is always followed by a layout. The PDF printer is selected if
+ // there are other printers but none of them was used.
+ PrintAttributes firstOldAttributes = new PrintAttributes.Builder().build();
+ PrintAttributes firstNewAttributes = new PrintAttributes.Builder()
+ .setMediaSize(MediaSize.NA_LETTER)
+ .setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
+ .setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
+
+ // We always ask for the first page for preview.
+ PageRange[] firstPages = new PageRange[] {new PageRange(0, 0)};
+ inOrder.verify(adapter).onWrite(eq(firstPages), any(ParcelFileDescriptor.class),
+ any(CancellationSignal.class), any(WriteResultCallback.class));
+
+ // Finish is always called last.
+ inOrder.verify(adapter).onFinish();
+
+ // No other call are expected.
+ verifyNoMoreInteractions(adapter);
+ }
+
+ private PrintServiceCallbacks createFirstMockPrintServiceCallbacks() {
+ final PrinterDiscoverySessionCallbacks callbacks =
+ createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ PrinterDiscoverySessionCallbacks mock = (PrinterDiscoverySessionCallbacks)
+ invocation.getMock();
+
+ StubbablePrinterDiscoverySession session = mock.getSession();
+ PrintService service = session.getService();
+
+ if (session.getPrinters().isEmpty()) {
+ List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
+
+ // Add the first printer.
+ PrinterId firstPrinterId = service.generatePrinterId("first_printer");
+ PrinterCapabilitiesInfo firstCapabilities =
+ new PrinterCapabilitiesInfo.Builder(firstPrinterId)
+ .setMinMargins(new Margins(200, 200, 200, 200))
+ .addMediaSize(MediaSize.ISO_A4, true)
+ .addMediaSize(MediaSize.ISO_A5, false)
+ .addResolution(new Resolution("300x300", "300x300", 300, 300), true)
+ .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+ PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ PrinterInfo firstPrinter = new PrinterInfo.Builder(firstPrinterId,
+ "First printer", PrinterInfo.STATUS_IDLE)
+ .setCapabilities(firstCapabilities)
+ .build();
+ printers.add(firstPrinter);
+
+ // Add the second printer.
+ PrinterId secondPrinterId = service.generatePrinterId("second_printer");
+ PrinterCapabilitiesInfo secondCapabilities =
+ new PrinterCapabilitiesInfo.Builder(secondPrinterId)
+ .addMediaSize(MediaSize.ISO_A3, true)
+ .addMediaSize(MediaSize.ISO_A4, false)
+ .addResolution(new Resolution("200x200", "200x200", 200, 200), true)
+ .addResolution(new Resolution("300x300", "300x300", 300, 300), false)
+ .setColorModes(PrintAttributes.COLOR_MODE_COLOR
+ | PrintAttributes.COLOR_MODE_MONOCHROME,
+ PrintAttributes.COLOR_MODE_MONOCHROME)
+ .build();
+ PrinterInfo secondPrinter = new PrinterInfo.Builder(secondPrinterId,
+ "Second printer", PrinterInfo.STATUS_IDLE)
+ .setCapabilities(secondCapabilities)
+ .build();
+ printers.add(secondPrinter);
+
+ // Add the third printer.
+ PrinterId thirdPrinterId = service.generatePrinterId("third_printer");
+ PrinterCapabilitiesInfo thirdCapabilities =
+ new PrinterCapabilitiesInfo.Builder(thirdPrinterId)
+ .addMediaSize(MediaSize.NA_LETTER, true)
+ .addResolution(new Resolution("300x300", "300x300", 300, 300), true)
+ .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+ PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+ PrinterInfo thirdPrinter = new PrinterInfo.Builder(thirdPrinterId,
+ "Third printer", PrinterInfo.STATUS_IDLE)
+ .setCapabilities(thirdCapabilities)
+ .build();
+ printers.add(thirdPrinter);
+
+ session.addPrinters(printers);
+ }
+ return null;
+ }
+ }, null, null, null, null, null);
+ return createMockPrintServiceCallbacks(new Answer<PrinterDiscoverySessionCallbacks>() {
+ @Override
+ public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+ return callbacks;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+ printJob.complete();
+ return null;
+ }
+ }, null);
+ }
+
+ private PrintServiceCallbacks createSecondMockPrintServiceCallbacks() {
+ return createMockPrintServiceCallbacks(null, null, null);
+ }
+}
diff --git a/tests/tests/print/src/android/print/cts/services/AddPrintersActivity.java b/tests/tests/print/src/android/print/cts/services/AddPrintersActivity.java
new file mode 100644
index 0000000..c72d6f9
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/services/AddPrintersActivity.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.cts.services;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class AddPrintersActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+}
diff --git a/tests/tests/print/src/android/print/cts/services/CustomPrintOptionsActivity.java b/tests/tests/print/src/android/print/cts/services/CustomPrintOptionsActivity.java
new file mode 100644
index 0000000..9d26d81
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/services/CustomPrintOptionsActivity.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.cts.services;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class CustomPrintOptionsActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+}
diff --git a/tests/tests/print/src/android/print/cts/services/FirstPrintService.java b/tests/tests/print/src/android/print/cts/services/FirstPrintService.java
new file mode 100644
index 0000000..a234de4
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/services/FirstPrintService.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.cts.services;
+
+public class FirstPrintService extends StubbablePrintService {
+
+ private static final Object sLock = new Object();
+
+ private static PrintServiceCallbacks sCallbacks;
+
+ public static void setCallbacks(PrintServiceCallbacks callbacks) {
+ synchronized (sLock) {
+ sCallbacks = callbacks;
+ }
+ }
+
+ @Override
+ protected PrintServiceCallbacks getCallbacks() {
+ synchronized (sLock) {
+ if (sCallbacks != null) {
+ sCallbacks.setService(this);
+ }
+ return sCallbacks;
+ }
+ }
+}
diff --git a/tests/tests/print/src/android/print/cts/services/PrintServiceCallbacks.java b/tests/tests/print/src/android/print/cts/services/PrintServiceCallbacks.java
new file mode 100644
index 0000000..ff0245f
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/services/PrintServiceCallbacks.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.cts.services;
+
+import android.printservice.PrintJob;
+import android.printservice.PrintService;
+
+public abstract class PrintServiceCallbacks {
+
+ private PrintService mService;
+
+ public PrintService getService() {
+ return mService;
+ }
+
+ public void setService(PrintService service) {
+ mService = service;
+ }
+
+ public abstract PrinterDiscoverySessionCallbacks onCreatePrinterDiscoverySessionCallbacks();
+
+ public abstract void onRequestCancelPrintJob(PrintJob printJob);
+
+ public abstract void onPrintJobQueued(PrintJob printJob);
+}
diff --git a/tests/tests/print/src/android/print/cts/services/PrinterDiscoverySessionCallbacks.java b/tests/tests/print/src/android/print/cts/services/PrinterDiscoverySessionCallbacks.java
new file mode 100644
index 0000000..6b2c3a9
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/services/PrinterDiscoverySessionCallbacks.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.cts.services;
+
+import android.print.PrinterId;
+
+import java.util.List;
+
+public abstract class PrinterDiscoverySessionCallbacks {
+
+ private StubbablePrinterDiscoverySession mSession;
+
+ public void setSession(StubbablePrinterDiscoverySession session) {
+ mSession = session;
+ }
+
+ public StubbablePrinterDiscoverySession getSession() {
+ return mSession;
+ }
+
+ public abstract void onStartPrinterDiscovery(List<PrinterId> priorityList);
+
+ public abstract void onStopPrinterDiscovery();
+
+ public abstract void onValidatePrinters(List<PrinterId> printerIds);
+
+ public abstract void onStartPrinterStateTracking(PrinterId printerId);
+
+ public abstract void onStopPrinterStateTracking(PrinterId printerId);
+
+ public abstract void onDestroy();
+}
diff --git a/tests/tests/print/src/android/print/cts/services/SecondPrintService.java b/tests/tests/print/src/android/print/cts/services/SecondPrintService.java
new file mode 100644
index 0000000..1029a8e
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/services/SecondPrintService.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.cts.services;
+
+public class SecondPrintService extends StubbablePrintService {
+
+ private static final Object sLock = new Object();
+
+ private static PrintServiceCallbacks sCallbacks;
+
+ public static void setCallbacks(PrintServiceCallbacks callbacks) {
+ synchronized (sLock) {
+ sCallbacks = callbacks;
+ }
+ }
+
+ @Override
+ protected PrintServiceCallbacks getCallbacks() {
+ synchronized (sLock) {
+ if (sCallbacks != null) {
+ sCallbacks.setService(this);
+ }
+ return sCallbacks;
+ }
+ }
+}
diff --git a/tests/tests/print/src/android/print/cts/services/SettingsActivity.java b/tests/tests/print/src/android/print/cts/services/SettingsActivity.java
new file mode 100644
index 0000000..eb23574
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/services/SettingsActivity.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.cts.services;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class SettingsActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+}
diff --git a/tests/tests/print/src/android/print/cts/services/StubbablePrintService.java b/tests/tests/print/src/android/print/cts/services/StubbablePrintService.java
new file mode 100644
index 0000000..2686b41
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/services/StubbablePrintService.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.cts.services;
+
+import android.printservice.PrintJob;
+import android.printservice.PrintService;
+import android.printservice.PrinterDiscoverySession;
+
+public abstract class StubbablePrintService extends PrintService {
+
+ @Override
+ public PrinterDiscoverySession onCreatePrinterDiscoverySession() {
+ PrintServiceCallbacks callbacks = getCallbacks();
+ if (callbacks != null) {
+ return new StubbablePrinterDiscoverySession(this,
+ getCallbacks().onCreatePrinterDiscoverySessionCallbacks());
+ }
+ return null;
+ }
+
+ @Override
+ public void onRequestCancelPrintJob(PrintJob printJob) {
+ PrintServiceCallbacks callbacks = getCallbacks();
+ if (callbacks != null) {
+ callbacks.onRequestCancelPrintJob(printJob);
+ }
+ }
+
+ @Override
+ public void onPrintJobQueued(PrintJob printJob) {
+ PrintServiceCallbacks callbacks = getCallbacks();
+ if (callbacks != null) {
+ callbacks.onPrintJobQueued(printJob);
+ }
+ }
+
+ protected abstract PrintServiceCallbacks getCallbacks();
+}
diff --git a/tests/tests/print/src/android/print/cts/services/StubbablePrinterDiscoverySession.java b/tests/tests/print/src/android/print/cts/services/StubbablePrinterDiscoverySession.java
new file mode 100644
index 0000000..fdc2713
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/services/StubbablePrinterDiscoverySession.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.cts.services;
+
+import android.print.PrinterId;
+import android.printservice.PrintService;
+import android.printservice.PrinterDiscoverySession;
+
+import java.util.List;
+
+public class StubbablePrinterDiscoverySession extends PrinterDiscoverySession {
+ private final PrintService mService;
+ private final PrinterDiscoverySessionCallbacks mCallbacks;
+
+ public StubbablePrinterDiscoverySession(PrintService service,
+ PrinterDiscoverySessionCallbacks callbacks) {
+ mService = service;
+ mCallbacks = callbacks;
+ if (mCallbacks != null) {
+ mCallbacks.setSession(this);
+ }
+ }
+
+ public PrintService getService() {
+ return mService;
+ }
+
+ @Override
+ public void onStartPrinterDiscovery(List<PrinterId> priorityList) {
+ if (mCallbacks != null) {
+ mCallbacks.onStartPrinterDiscovery(priorityList);
+ }
+ }
+
+ @Override
+ public void onStopPrinterDiscovery() {
+ if (mCallbacks != null) {
+ mCallbacks.onStopPrinterDiscovery();
+ }
+ }
+
+ @Override
+ public void onValidatePrinters(List<PrinterId> printerIds) {
+ if (mCallbacks != null) {
+ mCallbacks.onValidatePrinters(printerIds);
+ }
+ }
+
+ @Override
+ public void onStartPrinterStateTracking(PrinterId printerId) {
+ if (mCallbacks != null) {
+ mCallbacks.onStartPrinterStateTracking(printerId);
+ }
+ }
+
+ @Override
+ public void onStopPrinterStateTracking(PrinterId printerId) {
+ if (mCallbacks != null) {
+ mCallbacks.onStopPrinterStateTracking(printerId);
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ if (mCallbacks != null) {
+ mCallbacks.onDestroy();
+ }
+ }
+}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/YuvTest.java b/tests/tests/renderscript/src/android/renderscript/cts/YuvTest.java
index c2c7275..21f4417 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/YuvTest.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/YuvTest.java
@@ -58,16 +58,10 @@
bv[i] = (byte)r.nextInt(256);
}
- Type.Builder tb = new Type.Builder(mRS, Element.U8(mRS));
- tb.setX(w);
- tb.setY(h);
- ay = Allocation.createTyped(mRS, tb.create());
-
- tb = new Type.Builder(mRS, Element.U8(mRS));
- tb.setX(w >> 1);
- tb.setY(h >> 1);
- au = Allocation.createTyped(mRS, tb.create());
- av = Allocation.createTyped(mRS, tb.create());
+ ay = Allocation.createTyped(mRS, Type.createXY(mRS, Element.U8(mRS), w, h));
+ final Type tuv = Type.createXY(mRS, Element.U8(mRS), w >> 1, h >> 1);
+ au = Allocation.createTyped(mRS, tuv);
+ av = Allocation.createTyped(mRS, tuv);
ay.copyFrom(by);
au.copyFrom(bu);
@@ -75,11 +69,7 @@
}
public Allocation makeOutput() {
- Type.Builder tb = new Type.Builder(mRS, Element.RGBA_8888(mRS));
- tb.setX(width);
- tb.setY(height);
- Type t = tb.create();
- return Allocation.createTyped(mRS, t);
+ return Allocation.createTyped(mRS, Type.createXY(mRS, Element.RGBA_8888(mRS), width, height));
}
// Test for the API 17 conversion path
diff --git a/tests/tests/security/jni/android_security_cts_NativeCodeTest.cpp b/tests/tests/security/jni/android_security_cts_NativeCodeTest.cpp
index acb3012..1db8e97 100644
--- a/tests/tests/security/jni/android_security_cts_NativeCodeTest.cpp
+++ b/tests/tests/security/jni/android_security_cts_NativeCodeTest.cpp
@@ -15,9 +15,13 @@
*/
#include <jni.h>
+#include <linux/netlink.h>
+#include <linux/sock_diag.h>
+#include <stdio.h>
+#include <sys/socket.h>
#include <sys/types.h>
-#include <unistd.h>
#include <sys/syscall.h>
+#include <unistd.h>
#include <sys/prctl.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
@@ -25,6 +29,10 @@
#include <stdlib.h>
#include <cutils/log.h>
#include <linux/perf_event.h>
+#include <errno.h>
+
+#define PASSED 0
+#define UNKNOWN_ERROR -1
/*
* Returns true iff this device is vulnerable to CVE-2013-2094.
@@ -74,6 +82,73 @@
return true;
}
+/*
+ * Will hang if vulnerable, return 0 if successful, -1 on unforseen
+ * error.
+ */
+static jint android_security_cts_NativeCodeTest_doSockDiagTest(JNIEnv* env, jobject thiz)
+{
+ int fd, nlmsg_size, err, len;
+ char buf[1024];
+ struct sockaddr_nl nladdr;
+ struct nlmsghdr *nlh;
+ struct msghdr msg;
+ struct iovec iov;
+ struct sock_diag_req* sock_diag_data;
+
+ fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
+ if (fd == -1) {
+ switch (errno) {
+ /* NETLINK_SOCK_DIAG not accessible, vector dne */
+ case EACCES:
+ case EAFNOSUPPORT:
+ case EPERM:
+ case EPROTONOSUPPORT:
+ return PASSED;
+ default:
+ return UNKNOWN_ERROR;
+ }
+ }
+ /* prepare and send netlink packet */
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+ nlmsg_size = NLMSG_ALIGN(NLMSG_HDRLEN + sizeof(sock_diag_data));
+ nlh = (nlmsghdr *)malloc(nlmsg_size);
+ nlh->nlmsg_len = nlmsg_size;
+ nlh->nlmsg_pid = 0; //send packet to kernel
+ nlh->nlmsg_type = SOCK_DIAG_BY_FAMILY;
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ iov = { (void *) nlh, nlmsg_size };
+ msg = { (void *) &nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 };
+ sock_diag_data = (sock_diag_req *) NLMSG_DATA(nlh);
+ sock_diag_data->sdiag_family = AF_MAX+1;
+ if ((err = sendmsg(fd, &msg, 0)) == -1) {
+ /* SELinux blocked it */
+ if (errno == 22) {
+ return PASSED;
+ } else {
+ return UNKNOWN_ERROR;
+ }
+ }
+ free(nlh);
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ iov = { buf, sizeof(buf) };
+ msg = { (void *) &nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 };
+ if ((len = recvmsg(fd, &msg, 0)) == -1) {
+ return UNKNOWN_ERROR;
+ }
+ for (nlh = (struct nlmsghdr *) buf; NLMSG_OK(nlh, len); nlh = NLMSG_NEXT (nlh, len)){
+ if (nlh->nlmsg_type == NLMSG_ERROR) {
+ /* -22 = -EINVAL from kernel */
+ if (*(int *)NLMSG_DATA(nlh) == -22) {
+ return PASSED;
+ }
+ }
+ }
+ return UNKNOWN_ERROR;
+}
+
#define SEARCH_SIZE 0x4000
static int secret;
@@ -168,6 +243,8 @@
(void *) android_security_cts_NativeCodeTest_doPerfEventTest },
{ "doPerfEventTest2", "()Z",
(void *) android_security_cts_NativeCodeTest_doPerfEventTest2 },
+ { "doSockDiagTest", "()I",
+ (void *) android_security_cts_NativeCodeTest_doSockDiagTest },
{ "doVrootTest", "()Z",
(void *) android_security_cts_NativeCodeTest_doVrootTest },
};
diff --git a/tests/tests/security/src/android/security/cts/NativeCodeTest.java b/tests/tests/security/src/android/security/cts/NativeCodeTest.java
index 4781da3..30bf834 100644
--- a/tests/tests/security/src/android/security/cts/NativeCodeTest.java
+++ b/tests/tests/security/src/android/security/cts/NativeCodeTest.java
@@ -39,6 +39,12 @@
assertTrue(doPerfEventTest2());
}
+ public void testSockDiag() throws Exception {
+ int result = doSockDiagTest();
+ assertFalse("Encountered unexpected error: " + result + ".", (result == -1));
+ assertEquals(0, result);
+ }
+
/**
* Returns true iff this device is vulnerable to CVE-2013-2094.
* A patch for CVE-2013-2094 can be found at
@@ -62,7 +68,13 @@
private static native boolean doPerfEventTest2();
/**
- * ANDROID-11234878
+ * Hangs if device is vulnerable to CVE-2013-1763, returns -1 if
+ * unexpected error occurs, 0 otherwise.
+ */
+ private static native int doSockDiagTest();
+
+ /**
+ * ANDROID-11234878 / CVE-2013-6282
*
* Returns true if the device is patched against the vroot
* vulnerability. Returns false if there was some problem running
diff --git a/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java b/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
index 8c02d6b..7de3baa 100644
--- a/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
+++ b/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
@@ -99,7 +99,8 @@
try {
serviceBinder.dump(out.getFD(), new String[0]);
} catch (SecurityException e) {
- if (e.getMessage().contains("android.permission.DUMP")) {
+ String msg = e.getMessage();
+ if ((msg == null) || msg.contains("android.permission.DUMP")) {
// Service correctly checked for DUMP permission, yay
} else {
// Service is throwing about something else; they're
diff --git a/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java b/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java
index b33a312..66a86c3 100644
--- a/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java
+++ b/tests/tests/view/src/android/view/cts/LayoutInflaterTest.java
@@ -19,7 +19,6 @@
import com.android.cts.stub.R;
import com.android.internal.util.XmlUtils;
-
import org.xmlpull.v1.XmlPullParser;
import android.app.cts.MockActivity;
@@ -28,9 +27,11 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
+import android.content.res.Resources.Theme;
import android.content.res.XmlResourceParser;
import android.test.AndroidTestCase;
import android.util.AttributeSet;
+import android.util.TypedValue;
import android.util.Xml;
import android.view.Gravity;
import android.view.InflateException;
@@ -307,60 +308,76 @@
}
public void testInflate4() {
- XmlResourceParser parser = getContext().getResources().getLayout(
- R.layout.inflater_layout);
- View view = mLayoutInflater.inflate(parser, null, false);
- assertNotNull(view);
- view = null;
- try {
- view = mLayoutInflater.inflate(null, null, false);
- fail("should throw exception");
- } catch (NullPointerException e) {
- }
- LinearLayout mLayout;
- mLayout = new LinearLayout(mContext);
- mLayout.setOrientation(LinearLayout.VERTICAL);
- mLayout.setHorizontalGravity(Gravity.LEFT);
- mLayout.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
- assertEquals(0, mLayout.getChildCount());
+ XmlResourceParser parser = getContext().getResources().getLayout(
+ R.layout.inflater_layout);
+ View view = mLayoutInflater.inflate(parser, null, false);
+ assertNotNull(view);
+ view = null;
+ try {
+ view = mLayoutInflater.inflate(null, null, false);
+ fail("should throw exception");
+ } catch (NullPointerException e) {
+ }
+ LinearLayout mLayout;
+ mLayout = new LinearLayout(mContext);
+ mLayout.setOrientation(LinearLayout.VERTICAL);
+ mLayout.setHorizontalGravity(Gravity.LEFT);
+ mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ assertEquals(0, mLayout.getChildCount());
- try {
- view = mLayoutInflater.inflate(parser, mLayout, false);
- fail("should throw exception");
- } catch (NullPointerException e) {
- }
- parser = getContext().getResources().getLayout(
- R.layout.inflater_layout);
- view = mLayoutInflater.inflate(parser, mLayout, false);
- assertNull(view.getParent());
- assertNotNull(view);
- assertEquals(0, mLayout.getChildCount());
- parser = getContext().getResources().getLayout(
- R.layout.inflater_layout);
- assertEquals(0, mLayout.getChildCount());
- view = mLayoutInflater.inflate(parser, mLayout, true);
- assertNotNull(view);
- assertNull(view.getParent());
- assertEquals(1, mLayout.getChildCount());
+ try {
+ view = mLayoutInflater.inflate(parser, mLayout, false);
+ fail("should throw exception");
+ } catch (NullPointerException e) {
+ }
+ parser = getContext().getResources().getLayout(
+ R.layout.inflater_layout);
+ view = mLayoutInflater.inflate(parser, mLayout, false);
+ assertNull(view.getParent());
+ assertNotNull(view);
+ assertEquals(0, mLayout.getChildCount());
+ parser = getContext().getResources().getLayout(
+ R.layout.inflater_layout);
+ assertEquals(0, mLayout.getChildCount());
+ view = mLayoutInflater.inflate(parser, mLayout, true);
+ assertNotNull(view);
+ assertNull(view.getParent());
+ assertEquals(1, mLayout.getChildCount());
- parser = null;
- parser = getParser();
- try {
- view = mLayoutInflater.inflate(parser, mLayout, false);
- fail("should throw exception");
- } catch (InflateException e) {
- }
+ parser = null;
+ parser = getParser();
+ try {
+ view = mLayoutInflater.inflate(parser, mLayout, false);
+ fail("should throw exception");
+ } catch (InflateException e) {
+ }
- parser = null;
- view = null;
- parser = getParser();
+ parser = null;
+ view = null;
+ parser = getParser();
- view = mLayoutInflater.inflate(parser, mLayout, true);
- assertNotNull(view);
- assertEquals(2, mLayout.getChildCount());
- }
+ view = mLayoutInflater.inflate(parser, mLayout, true);
+ assertNotNull(view);
+ assertEquals(2, mLayout.getChildCount());
+ }
+
+ public void testOverrideTheme() {
+ View container = mLayoutInflater.inflate(R.layout.inflater_override_theme_layout, null);
+ verifyThemeType(container, "view_outer", R.id.view_outer, 1);
+ verifyThemeType(container, "view_inner", R.id.view_inner, 2);
+ }
+
+ private void verifyThemeType(View container, String tag, int id, int type) {
+ TypedValue outValue = new TypedValue();
+ View view = container.findViewById(id);
+ assertNotNull("Found " + tag, view);
+ Theme theme = view.getContext().getTheme();
+ boolean resolved = theme.resolveAttribute(R.attr.themeType, outValue, true);
+ assertTrue("Resolved themeType for " + tag, resolved);
+ assertEquals(tag + " has themeType " + type, outValue.data, type);
+ }
static class MockLayoutInflater extends LayoutInflater {
diff --git a/tests/tests/webkit/AndroidManifest.xml b/tests/tests/webkit/AndroidManifest.xml
index 493762e..f4424a8 100644
--- a/tests/tests/webkit/AndroidManifest.xml
+++ b/tests/tests/webkit/AndroidManifest.xml
@@ -22,6 +22,9 @@
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>
<application>
+ <provider android:name="android.webkit.cts.MockContentProvider"
+ android:exported="true"
+ android:authorities="android.webkit.cts.MockContentProvider" />
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/tests/webkit/src/android/webkit/cts/MockContentProvider.java b/tests/tests/webkit/src/android/webkit/cts/MockContentProvider.java
new file mode 100644
index 0000000..b9f3891
--- /dev/null
+++ b/tests/tests/webkit/src/android/webkit/cts/MockContentProvider.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2013 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.webkit.cts;
+
+import android.content.ContentProvider;
+import android.content.ContentProvider.PipeDataWriter;
+import android.content.ContentValues;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+
+public class MockContentProvider extends ContentProvider
+ implements PipeDataWriter<String> {
+
+ public static final String AUTHORITY = MockContentProvider.class.getName();
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return "text/html";
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues initialValues) {
+ return null;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ return null;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection,
+ String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public AssetFileDescriptor openAssetFile(Uri uri, String mode)
+ throws FileNotFoundException {
+ return new AssetFileDescriptor(openPipeHelper(uri, "text/html", null,
+ "<html><title>" + uri.toString() + "</title></html>", this), 0,
+ AssetFileDescriptor.UNKNOWN_LENGTH);
+ }
+
+ @Override
+ public void writeDataToPipe(ParcelFileDescriptor output, Uri uri, String mimeType, Bundle opts,
+ String args) {
+ FileOutputStream outputStream = new FileOutputStream(output.getFileDescriptor());
+ PrintWriter printWriter = null;
+ try {
+ printWriter = new PrintWriter(new OutputStreamWriter(outputStream, "UTF-8"));
+ printWriter.print(args);
+ } catch (UnsupportedEncodingException e) {
+ } finally {
+ if (printWriter != null) {
+ printWriter.flush();
+ }
+ try {
+ outputStream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+}
+
diff --git a/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java b/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java
index 11cc1a5..cc39f48 100644
--- a/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java
+++ b/tests/tests/webkit/src/android/webkit/cts/TestHtmlConstants.java
@@ -65,6 +65,7 @@
public static final String DATABASE_ACCESS_URL = "webkit/test_databaseaccess.html";
public static final String STOP_LOADING_URL = "webkit/test_stop_loading.html";
public static final String BLANK_TAG_URL = "webkit/blank_tag.html";
+ public static final String PAGE_WITH_LINK_URL = "webkit/page_with_link.html";
// Must match the title of the page at
// android/frameworks/base/core/res/res/raw/loaderror.html
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
index 5c9c958..344b568 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
@@ -112,6 +112,7 @@
Thread.sleep(100); // Wait for open to be received on the icon db thread.
assertFalse(webChromeClient.hadOnReceivedIcon());
+ assertNull(mOnUiThread.getFavicon());
String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
mOnUiThread.loadUrlAndWaitForCompletion(url);
@@ -122,6 +123,7 @@
return webChromeClient.hadOnReceivedIcon();
}
}.run();
+ assertNotNull(mOnUiThread.getFavicon());
}
public void runWindowTest(boolean expectWindowClose) throws Exception {
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
index f78c126..1027a59 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
@@ -80,11 +80,12 @@
"<a href=\"" + TEST_URL + "\" id=\"link\">new page</a>" +
"</body></html>";
mOnUiThread.loadDataAndWaitForCompletion(data, "text/html", null);
- clickOnLinkUsingJs("link");
+ clickOnLinkUsingJs("link", mOnUiThread);
assertEquals(TEST_URL, webViewClient.getLastShouldOverrideUrl());
}
// Verify shouldoverrideurlloading called on webview called via onCreateWindow
+ // TODO(sgurun) upstream this test to Aw.
public void testShouldOverrideUrlLoadingOnCreateWindow() throws Exception {
mWebServer = new CtsTestServer(getActivity());
// WebViewClient for main window
@@ -95,12 +96,14 @@
mOnUiThread.getSettings().setJavaScriptEnabled(true);
mOnUiThread.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
mOnUiThread.getSettings().setSupportMultipleWindows(true);
+
+ final WebView childWebView = mOnUiThread.createWebView();
+
mOnUiThread.setWebChromeClient(new WebChromeClient() {
@Override
public boolean onCreateWindow(
WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
- WebView childWebView = new WebView(view.getContext());
childWebView.setWebViewClient(childWebViewClient);
childWebView.getSettings().setJavaScriptEnabled(true);
transport.setWebView(childWebView);
@@ -119,13 +122,27 @@
return childWebViewClient.hasOnPageFinishedCalled();
}
}.run();
- assertEquals(mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL),
+ assertEquals(mWebServer.getAssetUrl(TestHtmlConstants.PAGE_WITH_LINK_URL),
childWebViewClient.getLastShouldOverrideUrl());
+
+ // Now test a navigation within the page
+ WebViewOnUiThread childWebViewOnUiThread = new WebViewOnUiThread(this, childWebView);
+ final int childCallCount = childWebViewClient.getShouldOverrideUrlLoadingCallCount();
+ final int mainCallCount = mainWebViewClient.getShouldOverrideUrlLoadingCallCount();
+ clickOnLinkUsingJs("link", childWebViewOnUiThread);
+ new PollingCheck(TEST_TIMEOUT) {
+ @Override
+ protected boolean check() {
+ return childWebViewClient.getShouldOverrideUrlLoadingCallCount() > childCallCount;
+ }
+ }.run();
+ assertEquals(mainCallCount, mainWebViewClient.getShouldOverrideUrlLoadingCallCount());
+ assertEquals(TEST_URL, childWebViewClient.getLastShouldOverrideUrl());
}
- private void clickOnLinkUsingJs(final String linkId) {
+ private void clickOnLinkUsingJs(final String linkId, WebViewOnUiThread webViewOnUiThread) {
EvaluateJsResultPollingCheck jsResult = new EvaluateJsResultPollingCheck("null");
- mOnUiThread.evaluateJavascript(
+ webViewOnUiThread.evaluateJavascript(
"document.getElementById('" + linkId + "').click();" +
"console.log('element with id [" + linkId + "] clicked');", jsResult);
jsResult.run();
@@ -287,6 +304,7 @@
private boolean mOnReceivedHttpAuthRequestCalled;
private boolean mOnUnhandledKeyEventCalled;
private boolean mOnScaleChangedCalled;
+ private int mShouldOverrideUrlLoadingCallCount;
private String mLastShouldOverrideUrl;
public MockWebViewClient() {
@@ -329,6 +347,10 @@
return mOnScaleChangedCalled;
}
+ public int getShouldOverrideUrlLoadingCallCount() {
+ return mShouldOverrideUrlLoadingCallCount;
+ }
+
public String getLastShouldOverrideUrl() {
return mLastShouldOverrideUrl;
}
@@ -395,6 +417,7 @@
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
mLastShouldOverrideUrl = url;
+ mShouldOverrideUrlLoadingCallCount++;
return false;
}
}
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index 1bec05c..cfe1a81 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -16,6 +16,7 @@
package android.webkit.cts;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetManager;
import android.cts.util.EvaluateJsResultPollingCheck;
@@ -79,7 +80,9 @@
import java.io.IOException;
import java.util.Collections;
import java.util.Date;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.HashMap;
@@ -140,7 +143,7 @@
protected void tearDown() throws Exception {
mOnUiThread.cleanUp();
if (mWebServer != null) {
- mWebServer.shutdown();
+ stopWebServer();
}
if (mIconDb != null) {
mIconDb.removeAllIcons();
@@ -358,6 +361,18 @@
}
@UiThreadTest
+ public void testLoadUrlDoesNotStripParamsWhenLoadingContentUrls() throws Exception {
+ Uri.Builder uriBuilder = new Uri.Builder().scheme(
+ ContentResolver.SCHEME_CONTENT).authority(MockContentProvider.AUTHORITY);
+ uriBuilder.appendPath("foo.html").appendQueryParameter("param","bar");
+ String url = uriBuilder.build().toString();
+ mOnUiThread.loadUrlAndWaitForCompletion(url);
+ // verify the parameter is not stripped.
+ Uri uri = Uri.parse(mWebView.getTitle());
+ assertEquals("bar", uri.getQueryParameter("param"));
+ }
+
+ @UiThreadTest
public void testAppInjectedXRequestedWithHeaderIsNotOverwritten() throws Exception {
startWebServer(false);
String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
@@ -651,6 +666,42 @@
assertEquals("removedObject", resultObject.getResult());
}
+ public void testAddJavascriptInterfaceExceptions() throws Exception {
+ WebSettings settings = mOnUiThread.getSettings();
+ settings.setJavaScriptEnabled(true);
+ settings.setJavaScriptCanOpenWindowsAutomatically(true);
+
+ final AtomicBoolean mJsInterfaceWasCalled = new AtomicBoolean(false) {
+ @JavascriptInterface
+ public synchronized void call() {
+ set(true);
+ // The main purpose of this test is to ensure an exception here does not
+ // crash the implementation.
+ throw new RuntimeException("Javascript Interface exception");
+ }
+ };
+
+ mOnUiThread.addJavascriptInterface(mJsInterfaceWasCalled, "dummy");
+
+ mOnUiThread.loadUrlAndWaitForCompletion("about:blank");
+
+ assertFalse(mJsInterfaceWasCalled.get());
+
+ final CountDownLatch resultLatch = new CountDownLatch(1);
+ mOnUiThread.evaluateJavascript(
+ "try {dummy.call(); 'fail'; } catch (exception) { 'pass'; } ",
+ new ValueCallback<String>() {
+ @Override
+ public void onReceiveValue(String result) {
+ assertEquals("\"pass\"", result);
+ resultLatch.countDown();
+ }
+ });
+
+ assertTrue(resultLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+ assertTrue(mJsInterfaceWasCalled.get());
+ }
+
public void testCapturePicture() throws Exception, Throwable {
startWebServer(false);
final String url = mWebServer.getAssetUrl(TestHtmlConstants.BLANK_PAGE_URL);
@@ -1438,16 +1489,6 @@
}
@UiThreadTest
- public void testGetFavicon() throws Exception {
- startWebServer(false);
- String url = mWebServer.getAssetUrl(TestHtmlConstants.TEST_FAVICON_URL);
- mOnUiThread.loadUrlAndWaitForCompletion(url);
- mWebView.getFavicon();
- // ToBeFixed: Favicon is not loaded automatically.
- // assertNotNull(mWebView.getFavicon());
- }
-
- @UiThreadTest
public void testClearHistory() throws Exception {
startWebServer(false);
String url1 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL1);
@@ -1509,7 +1550,7 @@
assertNotNull(restoreList);
assertEquals(3, restoreList.getSize());
assertEquals(2, saveList.getCurrentIndex());
- /* ToBeFixed: The WebHistoryItems do not get inflated. Uncomment remaining tests when fixed.
+
// wait for the list items to get inflated
new PollingCheck(TEST_TIMEOUT) {
@Override
@@ -1530,7 +1571,6 @@
assertEquals(url1, copyListAfterRestore.getItemAtIndex(0).getUrl());
assertEquals(url2, copyListAfterRestore.getItemAtIndex(1).getUrl());
assertEquals(url3, copyListAfterRestore.getItemAtIndex(2).getUrl());
- */
}
public void testSetWebViewClient() throws Throwable {
@@ -1743,6 +1783,35 @@
assertEquals("Second page", mOnUiThread.getTitle());
}
+ public void testSecureServerRequestingClientCertDoesNotCancelRequest() throws Throwable {
+ mWebServer = new CtsTestServer(getActivity(), CtsTestServer.SslMode.WANTS_CLIENT_AUTH);
+ final String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
+ final SslErrorWebViewClient webViewClient = new SslErrorWebViewClient();
+ mOnUiThread.setWebViewClient(webViewClient);
+ mOnUiThread.clearSslPreferences();
+ mOnUiThread.loadUrlAndWaitForCompletion(url);
+ // Page loaded OK...
+ assertTrue(webViewClient.wasOnReceivedSslErrorCalled());
+ assertEquals(TestHtmlConstants.HELLO_WORLD_TITLE, mOnUiThread.getTitle());
+ assertEquals(0, webViewClient.onReceivedErrorCode());
+ }
+
+ public void testSecureServerRequiringClientCertDoesCancelRequest() throws Throwable {
+ mWebServer = new CtsTestServer(getActivity(), CtsTestServer.SslMode.NEEDS_CLIENT_AUTH);
+ final String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
+ final SslErrorWebViewClient webViewClient = new SslErrorWebViewClient();
+ mOnUiThread.setWebViewClient(webViewClient);
+ mOnUiThread.clearSslPreferences();
+ mOnUiThread.loadUrlAndWaitForCompletion(url);
+ // Page NOT loaded OK...
+ // In this case, we must NOT have received the onReceivedSslError callback as that is for
+ // recoverable (e.g. server auth) errors, whereas failing mandatory client auth is non-
+ // recoverable and should drop straight through to a load error.
+ assertFalse(webViewClient.wasOnReceivedSslErrorCalled());
+ assertFalse(TestHtmlConstants.HELLO_WORLD_TITLE.equals(mOnUiThread.getTitle()));
+ assertEquals(WebViewClient.ERROR_FAILED_SSL_HANDSHAKE, webViewClient.onReceivedErrorCode());
+ }
+
public void testRequestChildRectangleOnScreen() throws Throwable {
DisplayMetrics metrics = mOnUiThread.getDisplayMetrics();
final int dimension = 2 * Math.max(metrics.widthPixels, metrics.heightPixels);
@@ -1767,12 +1836,12 @@
}
public void testSetDownloadListener() throws Throwable {
+ final CountDownLatch resultLatch = new CountDownLatch(1);
final class MyDownloadListener implements DownloadListener {
public String url;
public String mimeType;
public long contentLength;
public String contentDisposition;
- public boolean called;
@Override
public void onDownloadStart(String url, String userAgent, String contentDisposition,
@@ -1781,7 +1850,7 @@
this.mimeType = mimetype;
this.contentLength = contentLength;
this.contentDisposition = contentDisposition;
- this.called = true;
+ resultLatch.countDown();
}
}
@@ -1804,17 +1873,11 @@
// Wait for layout to complete before setting focus.
getInstrumentation().waitForIdleSync();
- new PollingCheck(TEST_TIMEOUT) {
- @Override
- protected boolean check() {
- return listener.called;
- }
- }.run();
+ assertTrue(resultLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
assertEquals(url, listener.url);
assertTrue(listener.contentDisposition.contains("test.bin"));
- // ToBeFixed: uncomment the following tests after fixing the framework
- // assertEquals(mimeType, listener.mimeType);
- // assertEquals(length, listener.contentLength);
+ assertEquals(length, listener.contentLength);
+ assertEquals(mimeType, listener.mimeType);
}
@UiThreadTest
@@ -2077,11 +2140,6 @@
});
}
- @UiThreadTest
- public void testInternals() {
- // Do not test these APIs. They are implementation details.
- }
-
private static class HrefCheckHandler extends Handler {
private boolean mHadRecieved;
@@ -2165,51 +2223,6 @@
}
}
- // Find b1 inside b2
- private boolean checkBitmapInsideAnother(Bitmap b1, Bitmap b2) {
- int w = b1.getWidth();
- int h = b1.getHeight();
-
- for (int i = 0; i < (b2.getWidth()-w+1); i++) {
- for (int j = 0; j < (b2.getHeight()-h+1); j++) {
- if (checkBitmapInsideAnother(b1, b2, i, j))
- return true;
- }
- }
- return false;
- }
-
- private boolean comparePixel(int p1, int p2, int maxError) {
- int err;
- err = Math.abs(((p1&0xff000000)>>>24) - ((p2&0xff000000)>>>24));
- if (err > maxError)
- return false;
-
- err = Math.abs(((p1&0x00ff0000)>>>16) - ((p2&0x00ff0000)>>>16));
- if (err > maxError)
- return false;
-
- err = Math.abs(((p1&0x0000ff00)>>>8) - ((p2&0x0000ff00)>>>8));
- if (err > maxError)
- return false;
-
- err = Math.abs(((p1&0x000000ff)>>>0) - ((p2&0x000000ff)>>>0));
- if (err > maxError)
- return false;
-
- return true;
- }
-
- private boolean checkBitmapInsideAnother(Bitmap b1, Bitmap b2, int x, int y) {
- for (int i = 0; i < b1.getWidth(); i++)
- for (int j = 0; j < b1.getHeight(); j++) {
- if (!comparePixel(b1.getPixel(i, j), b2.getPixel(x + i, y + j), 10)) {
- return false;
- }
- }
- return true;
- }
-
/**
* Waits at least MIN_SCROLL_WAIT_MS for scrolling to start. Once started,
* scrolling is checked every SCROLL_WAIT_INTERVAL_MS for changes. Once
@@ -2239,6 +2252,7 @@
final class SslErrorWebViewClient extends WaitForLoadedClient {
private boolean mWasOnReceivedSslErrorCalled;
private String mErrorUrl;
+ private int mErrorCode;
public SslErrorWebViewClient() {
super(mOnUiThread);
@@ -2249,6 +2263,11 @@
mErrorUrl = error.getUrl();
handler.proceed();
}
+ @Override
+ public void onReceivedError(WebView view, int errorCode, String description,
+ String failingUrl) {
+ mErrorCode = errorCode;
+ }
public void resetWasOnReceivedSslErrorCalled() {
mWasOnReceivedSslErrorCalled = false;
}
@@ -2258,6 +2277,9 @@
public String errorUrl() {
return mErrorUrl;
}
+ public int onReceivedErrorCode() {
+ return mErrorCode;
+ }
}
final class ScaleChangedWebViewClient extends WaitForLoadedClient {
diff --git a/tools/cts-java-scanner/src/com/android/cts/javascanner/DocletRunner.java b/tools/cts-java-scanner/src/com/android/cts/javascanner/DocletRunner.java
index e56a7cf..1cc86ca 100644
--- a/tools/cts-java-scanner/src/com/android/cts/javascanner/DocletRunner.java
+++ b/tools/cts-java-scanner/src/com/android/cts/javascanner/DocletRunner.java
@@ -77,8 +77,7 @@
sourcePath.add("./cts/tests/src");
sourcePath.add("./cts/libs/commonutil/src");
sourcePath.add("./cts/libs/deviceutil/src");
- sourcePath.add("./frameworks/testing/uiautomator/library/testrunner-src");
- sourcePath.add("./frameworks/testing/uiautomator_test_libraries/src");
+ sourcePath.add("./frameworks/uiautomator/src");
sourcePath.add(sourceDir.toString());
return join(sourcePath, ":");
}
diff --git a/tools/tradefed-host/etc/cts-tradefed b/tools/tradefed-host/etc/cts-tradefed
index 11f97e6..fb108b1 100755
--- a/tools/tradefed-host/etc/cts-tradefed
+++ b/tools/tradefed-host/etc/cts-tradefed
@@ -51,17 +51,21 @@
# check if in Android build env
-if [ ! -z ${ANDROID_BUILD_TOP} ]; then
- HOST=`uname`
- if [ "$HOST" == "Linux" ]; then
- OS="linux-x86"
- elif [ "$HOST" == "Darwin" ]; then
- OS="darwin-x86"
+if [ ! -z "${ANDROID_BUILD_TOP}" ]; then
+ if [ ! -z "${ANDROID_HOST_OUT}" ]; then
+ CTS_ROOT=${ANDROID_HOST_OUT}/cts
else
- echo "Unrecognized OS"
- exit
- fi;
- CTS_ROOT=${ANDROID_BUILD_TOP}/out/host/${OS}/cts
+ HOST=`uname`
+ if [ "$HOST" == "Linux" ]; then
+ OS="linux-x86"
+ elif [ "$HOST" == "Darwin" ]; then
+ OS="darwin-x86"
+ else
+ echo "Unrecognized OS"
+ exit
+ fi
+ CTS_ROOT=${ANDROID_BUILD_TOP}/${OUT_DIR:-out}/host/${OS}/cts
+ fi
if [ ! -d ${CTS_ROOT} ]; then
echo "Could not find $CTS_ROOT in Android build environment. Try 'make cts'"
exit
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
index c6977e5..48f4773 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
@@ -43,14 +43,13 @@
import com.android.tradefed.util.RunUtil;
import com.android.tradefed.util.xml.AbstractXmlParser.ParseException;
+import junit.framework.Test;
+
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
-import java.lang.InterruptedException;
-import java.lang.System;
-import java.lang.Thread;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -63,8 +62,6 @@
import java.util.Queue;
import java.util.Set;
-import junit.framework.Test;
-
/**
* A {@link Test} for running CTS tests.
* <p/>
@@ -600,8 +597,13 @@
for (String uri : plan.getTestUris()) {
if (!mExcludedPackageNames.contains(uri)) {
ITestPackageDef testPackage = testRepo.getTestPackage(uri);
- testPackage.setExcludedTestFilter(plan.getExcludedTestFilter(uri));
- testPkgDefs.add(testPackage);
+ if (testPackage != null) {
+ testPackage.setExcludedTestFilter(plan.getExcludedTestFilter(uri));
+ testPkgDefs.add(testPackage);
+ } else {
+ CLog.e("Could not find test package uri %s referenced in plan %s", uri,
+ mPlanName);
+ }
}
}
} else if (mPackageNames.size() > 0){
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/PrintTestRemoteTestRunner.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/PrintTestRemoteTestRunner.java
new file mode 100644
index 0000000..3d92eb3
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/PrintTestRemoteTestRunner.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.tradefed.testtype;
+
+import com.android.ddmlib.AdbCommandRejectedException;
+import com.android.ddmlib.IShellEnabledDevice;
+import com.android.ddmlib.Log;
+import com.android.ddmlib.ShellCommandUnresponsiveException;
+import com.android.ddmlib.TimeoutException;
+import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner;
+import com.android.ddmlib.testrunner.ITestRunListener;
+import com.android.ddmlib.testrunner.InstrumentationResultParser;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.TimeUnit;
+
+public class PrintTestRemoteTestRunner implements IRemoteAndroidTestRunner {
+
+ private final String mPackageName;
+ private final String mRunnerName;
+ private IShellEnabledDevice mRemoteDevice;
+ // default to no timeout
+ private long mMaxTimeToOutputResponse = 0;
+ private TimeUnit mMaxTimeUnits = TimeUnit.MILLISECONDS;
+ private String mRunName = null;
+
+ /** map of name-value instrumentation argument pairs */
+ private Map<String, String> mArgMap;
+ private InstrumentationResultParser mParser;
+
+ private static final String LOG_TAG = "RemoteAndroidTest";
+ private static final String DEFAULT_RUNNER_NAME = "android.test.InstrumentationTestRunner";
+
+ private static final char CLASS_SEPARATOR = ',';
+ private static final char METHOD_SEPARATOR = '#';
+ private static final char RUNNER_SEPARATOR = '/';
+
+ // defined instrumentation argument names
+ private static final String CLASS_ARG_NAME = "class";
+ private static final String LOG_ARG_NAME = "log";
+ private static final String DEBUG_ARG_NAME = "debug";
+ private static final String COVERAGE_ARG_NAME = "coverage";
+ private static final String PACKAGE_ARG_NAME = "package";
+ private static final String SIZE_ARG_NAME = "size";
+
+ // This command starts a shell Java program (installed by this class)
+ // in the folder owned by the shell user. This app creates a proxy
+ // which does privileged operations such as wiping a package's user
+ // data and then starts the tests passing the proxy. This enables
+ // the tests to clear the print spooler data.
+ private static final String INSTRUMENTATION_COMMAND =
+ "chmod 755 /data/local/tmp/print-instrument && "
+ + "/data/local/tmp/print-instrument instrument -w -r %1$s %2$s";
+
+ /**
+ * Creates a remote Android test runner.
+ *
+ * @param packageName the Android application package that contains the
+ * tests to run
+ * @param runnerName the instrumentation test runner to execute. If null,
+ * will use default runner
+ * @param remoteDevice the Android device to execute tests on
+ */
+ public PrintTestRemoteTestRunner(String packageName, String runnerName,
+ IShellEnabledDevice remoteDevice) {
+
+ mPackageName = packageName;
+ mRunnerName = runnerName;
+ mRemoteDevice = remoteDevice;
+ mArgMap = new Hashtable<String, String>();
+ }
+
+ /**
+ * Alternate constructor. Uses default instrumentation runner.
+ *
+ * @param packageName the Android application package that contains the
+ * tests to run
+ * @param remoteDevice the Android device to execute tests on
+ */
+ public PrintTestRemoteTestRunner(String packageName, IShellEnabledDevice remoteDevice) {
+ this(packageName, null, remoteDevice);
+ }
+
+ @Override
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ @Override
+ public String getRunnerName() {
+ if (mRunnerName == null) {
+ return DEFAULT_RUNNER_NAME;
+ }
+ return mRunnerName;
+ }
+
+ /**
+ * Returns the complete instrumentation component path.
+ */
+ private String getRunnerPath() {
+ return getPackageName() + RUNNER_SEPARATOR + getRunnerName();
+ }
+
+ @Override
+ public void setClassName(String className) {
+ addInstrumentationArg(CLASS_ARG_NAME, className);
+ }
+
+ @Override
+ public void setClassNames(String[] classNames) {
+ StringBuilder classArgBuilder = new StringBuilder();
+
+ for (int i = 0; i < classNames.length; i++) {
+ if (i != 0) {
+ classArgBuilder.append(CLASS_SEPARATOR);
+ }
+ classArgBuilder.append(classNames[i]);
+ }
+ setClassName(classArgBuilder.toString());
+ }
+
+ @Override
+ public void setMethodName(String className, String testName) {
+ setClassName(className + METHOD_SEPARATOR + testName);
+ }
+
+ @Override
+ public void setTestPackageName(String packageName) {
+ addInstrumentationArg(PACKAGE_ARG_NAME, packageName);
+ }
+
+ @Override
+ public void addInstrumentationArg(String name, String value) {
+ if (name == null || value == null) {
+ throw new IllegalArgumentException("name or value arguments cannot be null");
+ }
+ mArgMap.put(name, value);
+ }
+
+ @Override
+ public void removeInstrumentationArg(String name) {
+ if (name == null) {
+ throw new IllegalArgumentException("name argument cannot be null");
+ }
+ mArgMap.remove(name);
+ }
+
+ @Override
+ public void addBooleanArg(String name, boolean value) {
+ addInstrumentationArg(name, Boolean.toString(value));
+ }
+
+ @Override
+ public void setLogOnly(boolean logOnly) {
+ addBooleanArg(LOG_ARG_NAME, logOnly);
+ }
+
+ @Override
+ public void setDebug(boolean debug) {
+ addBooleanArg(DEBUG_ARG_NAME, debug);
+ }
+
+ @Override
+ public void setCoverage(boolean coverage) {
+ addBooleanArg(COVERAGE_ARG_NAME, coverage);
+ }
+
+ @Override
+ public void setTestSize(TestSize size) {
+ addInstrumentationArg(SIZE_ARG_NAME, ""/*size.getRunnerValue()*/);
+ }
+
+ @Override
+ public void setMaxtimeToOutputResponse(int maxTimeToOutputResponse) {
+ setMaxTimeToOutputResponse(maxTimeToOutputResponse, TimeUnit.MILLISECONDS);
+ }
+
+ @Override
+ public void setMaxTimeToOutputResponse(long maxTimeToOutputResponse, TimeUnit maxTimeUnits) {
+ mMaxTimeToOutputResponse = maxTimeToOutputResponse;
+ mMaxTimeUnits = maxTimeUnits;
+ }
+
+ @Override
+ public void setRunName(String runName) {
+ mRunName = runName;
+ }
+
+ @Override
+ public void run(ITestRunListener... listeners) throws TimeoutException,
+ AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException {
+ run(Arrays.asList(listeners));
+ }
+
+ @Override
+ public void run(Collection<ITestRunListener> listeners) throws TimeoutException,
+ AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException {
+ final String runCaseCommandStr = String.format(INSTRUMENTATION_COMMAND,
+ getArgsCommand(), getRunnerPath());
+ Log.i(LOG_TAG,
+ String.format("Running %1$s on %2$s", runCaseCommandStr, mRemoteDevice.getName()));
+ String runName = mRunName == null ? mPackageName : mRunName;
+ mParser = new InstrumentationResultParser(runName, listeners);
+
+ try {
+ mRemoteDevice.executeShellCommand(runCaseCommandStr, mParser, mMaxTimeToOutputResponse,
+ mMaxTimeUnits);
+ } catch (IOException e) {
+ Log.w(LOG_TAG, String.format("IOException %1$s when running tests %2$s on %3$s",
+ e.toString(), getPackageName(), mRemoteDevice.getName()));
+ // rely on parser to communicate results to listeners
+ mParser.handleTestRunFailed(e.toString());
+ throw e;
+ } catch (ShellCommandUnresponsiveException e) {
+ Log.w(LOG_TAG, String.format(
+ "ShellCommandUnresponsiveException %1$s when running tests %2$s on %3$s",
+ e.toString(), getPackageName(), mRemoteDevice.getName()));
+ mParser.handleTestRunFailed(String
+ .format("Failed to receive adb shell test output within %1$d ms. "
+ + "Test may have timed out, or adb connection to device became"
+ + "unresponsive", mMaxTimeToOutputResponse));
+ throw e;
+ } catch (TimeoutException e) {
+ Log.w(LOG_TAG, String.format("TimeoutException when running tests %1$s on %2$s",
+ getPackageName(), mRemoteDevice.getName()));
+ mParser.handleTestRunFailed(e.toString());
+ throw e;
+ } catch (AdbCommandRejectedException e) {
+ Log.w(LOG_TAG, String.format(
+ "AdbCommandRejectedException %1$s when running tests %2$s on %3$s",
+ e.toString(), getPackageName(), mRemoteDevice.getName()));
+ mParser.handleTestRunFailed(e.toString());
+ throw e;
+ }
+ }
+
+ @Override
+ public void cancel() {
+ if (mParser != null) {
+ mParser.cancel();
+ }
+ }
+
+ /**
+ * Returns the full instrumentation command line syntax for the provided
+ * instrumentation arguments. Returns an empty string if no arguments were
+ * specified.
+ */
+ private String getArgsCommand() {
+ StringBuilder commandBuilder = new StringBuilder();
+ for (Entry<String, String> argPair : mArgMap.entrySet()) {
+ final String argCmd = String.format(" -e %1$s %2$s", argPair.getKey(),
+ argPair.getValue());
+ commandBuilder.append(argCmd);
+ }
+ return commandBuilder.toString();
+ }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/PrintTestRunner.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/PrintTestRunner.java
new file mode 100644
index 0000000..a7a6ccc
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/PrintTestRunner.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.tradefed.testtype;
+
+import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.cts.tradefed.targetprep.SettingsToggler;
+import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner;
+import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner.TestSize;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.util.StringEscapeUtils;
+
+import java.io.FileNotFoundException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Running the print tests requires modification of secure settings. Secure
+ * settings cannot be changed from device CTS tests since system signature
+ * permission is required. Such settings can be modified by the shell user,
+ * so a host side test driver is used for enabling these services, running
+ * the tests, and disabling the services.
+ */
+public class PrintTestRunner implements IBuildReceiver, IRemoteTest, IDeviceTest {
+
+ private static final String PRINT_TEST_AND_SERVICES_APP_NAME =
+ "CtsPrintTestCases.apk";
+
+ private static final String PRINT_TESTS_PACKAGE_NAME =
+ "com.android.cts.print";
+
+ private static final String FIRST_PRINT_SERVICE_NAME =
+ "android.print.cts.services.FirstPrintService";
+
+ private static final String SECOND_PRINT_SERVICE_NAME =
+ "android.print.cts.services.SecondPrintService";
+
+ private static final String SHELL_USER_FOLDER = "data/local/tmp";
+
+ private static final String PRINT_INSTRUMENT_JAR = "CtsPrintInstrument.jar";
+
+ private static final String PRINT_INSTRUMENT_SCRIPT = "print-instrument";
+
+ private ITestDevice mDevice;
+
+ private CtsBuildHelper mCtsBuild;
+
+ private String mPackageName;
+ private String mRunnerName = "android.test.InstrumentationTestRunner";
+ private String mTestClassName;
+ private String mTestMethodName;
+ private String mTestPackageName;
+ private int mTestTimeout = 10 * 60 * 1000; // 10 minutes
+ private String mTestSize;
+ private String mRunName = null;
+ private Map<String, String> mInstrArgMap = new HashMap<String, String>();
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+ }
+
+ @Override
+ public void setDevice(ITestDevice device) {
+ mDevice = device;
+ }
+
+ @Override
+ public ITestDevice getDevice() {
+ return mDevice;
+ }
+
+ public void setPackageName(String packageName) {
+ mPackageName = packageName;
+ }
+
+ public void setRunnerName(String runnerName) {
+ mRunnerName = runnerName;
+ }
+
+ public void setClassName(String testClassName) {
+ mTestClassName = testClassName;
+ }
+
+ public void setMethodName(String testMethodName) {
+ mTestMethodName = StringEscapeUtils.escapeShell(testMethodName);
+ }
+
+ public void setTestPackageName(String testPackageName) {
+ mTestPackageName = testPackageName;
+ }
+
+ public void setTestSize(String size) {
+ mTestSize = size;
+ }
+
+ public void setRunName(String runName) {
+ mRunName = runName;
+ }
+
+ @Override
+ public void run(final ITestInvocationListener listener) throws DeviceNotAvailableException {
+ installShellProgramAndScriptFiles();
+ installTestsAndServicesApk();
+ enablePrintServices();
+ doRunTests(listener);
+ disablePrintServices();
+ uninstallTestsAndServicesApk();
+ uninstallShellProgramAndScriptFiles();
+ }
+
+ private void doRunTests(ITestInvocationListener listener)
+ throws DeviceNotAvailableException {
+ if (mPackageName == null) {
+ throw new IllegalArgumentException("package name has not been set");
+ }
+ if (mDevice == null) {
+ throw new IllegalArgumentException("Device has not been set");
+ }
+
+ IRemoteAndroidTestRunner runner = new PrintTestRemoteTestRunner(mPackageName,
+ mRunnerName, mDevice.getIDevice());
+
+ if (mTestClassName != null) {
+ if (mTestMethodName != null) {
+ runner.setMethodName(mTestClassName, mTestMethodName);
+ } else {
+ runner.setClassName(mTestClassName);
+ }
+ } else if (mTestPackageName != null) {
+ runner.setTestPackageName(mTestPackageName);
+ }
+ if (mTestSize != null) {
+ runner.setTestSize(TestSize.getTestSize(mTestSize));
+ }
+ runner.setMaxTimeToOutputResponse(mTestTimeout, TimeUnit.MILLISECONDS);
+ if (mRunName != null) {
+ runner.setRunName(mRunName);
+ }
+ for (Map.Entry<String, String> argEntry : mInstrArgMap.entrySet()) {
+ runner.addInstrumentationArg(argEntry.getKey(), argEntry.getValue());
+ }
+
+ mDevice.runInstrumentationTests(runner, listener);
+ }
+
+ private void installShellProgramAndScriptFiles() throws DeviceNotAvailableException {
+ installFile(PRINT_INSTRUMENT_JAR);
+ installFile(PRINT_INSTRUMENT_SCRIPT);
+ }
+
+ private void installFile(String fileName) throws DeviceNotAvailableException {
+ try {
+ final boolean success = getDevice().pushFile(mCtsBuild.getTestApp(
+ fileName), SHELL_USER_FOLDER + "/" + fileName);
+ if (!success) {
+ throw new IllegalArgumentException("Failed to install "
+ + fileName + " on " + getDevice().getSerialNumber());
+ }
+ } catch (FileNotFoundException fnfe) {
+ throw new IllegalArgumentException("Cannot find file: " + fileName);
+ }
+ }
+
+ private void uninstallShellProgramAndScriptFiles() throws DeviceNotAvailableException {
+ getDevice().executeShellCommand("rm " + SHELL_USER_FOLDER + "/"
+ + PRINT_INSTRUMENT_JAR);
+ getDevice().executeShellCommand("rm " + SHELL_USER_FOLDER + "/"
+ + PRINT_INSTRUMENT_SCRIPT);
+ }
+
+ private void installTestsAndServicesApk() throws DeviceNotAvailableException {
+ try {
+ String installCode = getDevice().installPackage(mCtsBuild.getTestApp(
+ PRINT_TEST_AND_SERVICES_APP_NAME), true);
+ if (installCode != null) {
+ throw new IllegalArgumentException("Failed to install "
+ + PRINT_TEST_AND_SERVICES_APP_NAME + " on " + getDevice().getSerialNumber()
+ + ". Reason: " + installCode);
+ }
+ } catch (FileNotFoundException fnfe) {
+ throw new IllegalArgumentException("Cannot find file: "
+ + PRINT_TEST_AND_SERVICES_APP_NAME);
+ }
+ }
+
+ private void uninstallTestsAndServicesApk() throws DeviceNotAvailableException {
+ getDevice().uninstallPackage(PRINT_TESTS_PACKAGE_NAME);
+ }
+
+ private void enablePrintServices() throws DeviceNotAvailableException {
+ String enabledServicesValue = PRINT_TESTS_PACKAGE_NAME + "/" + FIRST_PRINT_SERVICE_NAME
+ + ":" + PRINT_TESTS_PACKAGE_NAME + "/" + SECOND_PRINT_SERVICE_NAME;
+ SettingsToggler.setSecureString(getDevice(), "enabled_print_services",
+ enabledServicesValue);
+ }
+
+ private void disablePrintServices() throws DeviceNotAvailableException {
+ SettingsToggler.setSecureString(getDevice(), "enabled_print_services", "");
+ }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestFilter.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestFilter.java
index 053b265..448f067 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestFilter.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestFilter.java
@@ -25,6 +25,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.regex.Pattern;
/**
* Filter for {@link TestIdentifier}s.
@@ -34,7 +35,7 @@
private final Set<String> mExcludedClasses;
private final Set<TestIdentifier> mExcludedTests;
private String mIncludedClass = null;
- private String mIncludedMethod = null;
+ private Pattern mIncludedMethod = null;
/**
* Creates a {@link TestFilter}
@@ -87,7 +88,9 @@
*/
public void setTestInclusion(String className, String method) {
mIncludedClass = className;
- mIncludedMethod = method;
+ if (method != null) {
+ mIncludedMethod = Pattern.compile(method);
+ }
}
/**
@@ -103,7 +106,7 @@
// skip
continue;
}
- if (mIncludedMethod != null && !test.getTestName().equals(mIncludedMethod)) {
+ if (mIncludedMethod != null && !mIncludedMethod.matcher(test.getTestName()).matches()) {
// skip
continue;
}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
index 8ab5d18..994da0b 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
@@ -47,9 +47,11 @@
public static final String WRAPPED_NATIVE_TEST = "wrappednative";
public static final String VM_HOST_TEST = "vmHostTest";
public static final String ACCESSIBILITY_TEST =
- "com.android.cts.tradefed.testtype.AccessibilityTestRunner";
+ "com.android.cts.tradefed.testtype.AccessibilityTestRunner";
public static final String ACCESSIBILITY_SERVICE_TEST =
- "com.android.cts.tradefed.testtype.AccessibilityServiceTestRunner";
+ "com.android.cts.tradefed.testtype.AccessibilityServiceTestRunner";
+ public static final String PRINT_TEST =
+ "com.android.cts.tradefed.testtype.PrintTestRunner";
public static final String DISPLAY_TEST =
"com.android.cts.tradefed.testtype.DisplayTestRunner";
public static final String UIAUTOMATOR_TEST = "uiAutomator";
@@ -61,7 +63,6 @@
private String mAppNameSpace = null;
private String mName = null;
private String mRunner = null;
- private boolean mIsVMHostTest = false;
private String mTestType = null;
private String mJarPath = null;
private boolean mIsSignatureTest = false;
@@ -230,6 +231,9 @@
} else if (ACCESSIBILITY_TEST.equals(mTestType)) {
AccessibilityTestRunner test = new AccessibilityTestRunner();
return setInstrumentationTest(test, testCaseDir);
+ } else if (PRINT_TEST.equals(mTestType)) {
+ PrintTestRunner test = new PrintTestRunner();
+ return setPrintTest(test, testCaseDir);
} else if (ACCESSIBILITY_SERVICE_TEST.equals(mTestType)) {
AccessibilityServiceTestRunner test = new AccessibilityServiceTestRunner();
return setInstrumentationTest(test, testCaseDir);
@@ -270,6 +274,18 @@
}
}
+ private PrintTestRunner setPrintTest(PrintTestRunner printTest,
+ File testCaseDir) {
+ printTest.setRunName(getUri());
+ printTest.setPackageName(mAppNameSpace);
+ printTest.setRunnerName(mRunner);
+ printTest.setTestPackageName(mTestPackageName);
+ printTest.setClassName(mClassName);
+ printTest.setMethodName(mMethodName);
+ mDigest = generateDigest(testCaseDir, String.format("%s.apk", mName));
+ return printTest;
+ }
+
/**
* Populates given {@link InstrumentationApkTest} with data from the package xml.
*
diff --git a/tools/utils/buildCts.py b/tools/utils/buildCts.py
index b269be8..cb70c54 100755
--- a/tools/utils/buildCts.py
+++ b/tools/utils/buildCts.py
@@ -126,8 +126,14 @@
plan = tools.TestPlan(packages)
plan.Include(r'android\.core\.tests.*')
+ plan.Exclude(r'android\.core\.tests\.libcore.\package.\harmony*')
self.__WritePlan(plan, 'Java')
+ # TODO: remove this once the tests are fixed and merged into Java plan above.
+ plan = tools.TestPlan(packages)
+ plan.Include(r'android\.core\.tests\.libcore.\package.\harmony*')
+ self.__WritePlan(plan, 'Harmony')
+
plan = tools.TestPlan(packages)
plan.Include(r'android\.core\.vm-tests-tf')
self.__WritePlan(plan, 'VM-TF')
diff --git a/tools/vm-tests-tf/etc/starttests b/tools/vm-tests-tf/etc/starttests
new file mode 100755
index 0000000..0c8721b
--- /dev/null
+++ b/tools/vm-tests-tf/etc/starttests
@@ -0,0 +1,296 @@
+#!/bin/bash
+#
+# Copyright (C) 2008 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.
+
+# Set up prog to be the path of this script, including following symlinks,
+# and set up progdir to be the fully-qualified pathname of its directory.
+
+prog="$0"
+while [ -h "${prog}" ]; do
+ newProg=`/bin/ls -ld "${prog}"`
+ newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
+ if expr "x${newProg}" : 'x/' >/dev/null; then
+ prog="${newProg}"
+ else
+ progdir=`dirname "${prog}"`
+ prog="${progdir}/${newProg}"
+ fi
+done
+oldwd=`pwd`
+progdir=`dirname "${prog}"`
+cd "${progdir}"
+progdir=`pwd`
+prog="${progdir}"/`basename "${prog}"`
+cd "${oldwd}"
+
+libdir=`dirname $progdir`/framework
+
+javaOpts=""
+while expr "x$1" : 'x-J' >/dev/null; do
+ opt=`expr "$1" : '-J\(.*\)'`
+ javaOpts="${javaOpts} -${opt}"
+ shift
+done
+
+
+#######################################################################
+# Original content of invocation script follows. Uses values cleverly
+# deduced by the above code.
+#######################################################################
+
+selection=$1
+interpreter="fast"
+if [ "$selection" = "--portable" ]; then
+ selection=$2;
+ interpreter="portable"
+fi
+
+dalviktest=$ANDROID_BUILD_TOP/out/host/common/obj/JAVA_LIBRARIES/vm-tests-tf_intermediates
+dalviktestdir=$dalviktest/tests
+dexcore=$dalviktest/tests/dot/junit/dexcore.jar
+scriptdata=$dalviktestdir/data/scriptdata
+report=$dalviktest/report.html
+curdate=`date`
+curmode=""
+datadir=/tmp/${USER}
+base=$OUT
+framework=$base/system/framework
+export ANDROID_PRINTF_LOG=tag
+export ANDROID_LOG_TAGS='*:s' # was: jdwp:i dalvikvm:i dalvikvmi:i'
+export ANDROID_DATA=$datadir
+export ANDROID_ROOT=$base/system
+export LD_LIBRARY_PATH=$base/system/lib
+export DYLD_LIBRARY_PATH=$base/system/lib
+debug_opts="-Xcheck:jni -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n"
+exe=$base/system/bin/dalvikvm
+bpath=$framework/core.jar
+
+echo "--------------------------------------------------"
+echo "Dalvik VM Test Suite"
+echo "Version 1.0"
+echo "Copyright (c) 2008 The Android Open Source Project"
+echo ""
+
+if [ "$selection" = "--help" ]; then
+ echo "Usage: vm-tests [--help|--portable] [<mnemonic>]"
+ echo ""
+ echo " --help prints this help message"
+ echo " --portable uses the portable interpreter;"
+ echo " default is the fast one"
+ echo ""
+ echo " <mnemonic> specifies the instruction to test;"
+ echo " default is to run all tests"
+ echo ""
+ exit 1;
+fi
+
+rm -rf --preserve-root $datadir/dalvik-cache
+mkdir -p $datadir
+mkdir -p $datadir/dalvik-cache
+
+if [ "$TARGET_SIMULATOR" = "true" ]; then
+ echo "Simulator mode, $interpreter interpreter";
+ curmode="simulator"
+else
+ echo "Emulator mode, $interpreter interpreter";
+ curmode="emulator"
+fi
+
+echo ""
+
+pre_report="<html><head><style>
+table tr.ok { background:#a0ffa0; }
+table tr.nok { background:#ffa0a0; }
+table tr.wok { background:#ffffa0; }
+table tr.lok { background:#aaaaff; }
+</style></head>
+<body>
+<h1>Dalvik VM test suite results</h1>
+Generated $curdate (using the $curmode)
+<p>
+<table width='100%'>
+<tr><td>Status</td><td>Target</td><td>Category</td><td>Details</td></tr>"
+post_report="</body></html>"
+
+rm -f $report
+echo $pre_report > $report
+
+# ----------- running each opcode test ------------
+
+export jpassedcnt=0
+export jfailedcnt=0
+export jvfefailedcnt=0
+export jwarningcnt=0
+export jallcnt=0
+export jcolumns=0
+
+# TODO unhack
+if [ "$TARGET_SIMULATOR" = "true" ]; then
+ echo -n ""
+else
+ adb push $dexcore /data/local/tmp/dexcore.jar >> /dev/null 2>&1
+fi
+
+function classnameToJar()
+{
+ echo $1 | sed -e 's#\.#/#g;s#$#.jar#'
+}
+
+while read -u 3 myline;
+do
+ # dot.junit.opcodes.add_double.Main_testB1;dot.junit.opcodes.add_double.d.T_add_double_1 ;opcode add_double;test B #1 (border edge case)
+ # ->
+ # mainclass: dot.junit.opcodes.add_double.Main_testB1
+ # testcasedir: opcodes/add_double
+ # testname: testB1 ->
+ # dir dot/junit/opcodes/add_double/testB1
+
+ # e.g dot.junit.opcodes.add_double.Main_testB1
+ mainclass=`echo $myline | cut -d";" -f1`
+ # e.g dot.junit.opcodes.add_double.d.T_add_double_1, space sep. >=1 entries
+ deps=`echo $myline | cut -d";" -f2`
+
+ jtitle=`echo $myline | cut -d";" -f3`
+ jcomment=`echo $myline | cut -d";" -f4`
+ details=`echo $myline | cut -d";" -f5`
+
+ if [ "$selection" == "" ] || [ "$jtitle" == "$selection" ]; then
+
+ (( jallcnt += 1 ))
+
+ cd $dalviktestdir
+ rm -f $datadir/dalvikout
+ # write dalvik output to file
+ echo -n "mk_b:" > $datadir/dalvikout
+
+ if [ "$TARGET_SIMULATOR" = "true" ]; then
+ classpath=`classnameToJar ${mainclass}`
+ for dep in ${deps}; do
+ depJar=`classnameToJar ${dep}`
+ classpath=${classpath}:${depJar}
+ done
+ $valgrind $exe -Xint:$interpreter -Xmx512M -Xss32K -Xbootclasspath:$bpath $debug_opts \
+ -classpath $dexcore:$classpath $mainclass >> $datadir/dalvikout 2>&1
+
+ RESULTCODE=$?
+ if [ ${RESULTCODE} -ne 0 ]; then
+ echo "Dalvik VM failed, result=${RESULTCODE}" >> $datadir/dalvikout 2>&1
+ fi
+ else
+ classpath="/data/local/tmp/dexcore.jar"
+ deps=${deps}" "${mainclass}
+ pushedjars=""
+ for dep in ${deps}; do
+ depJar=`classnameToJar ${dep}`
+ depFileName=`basename ${depJar}`
+ deviceFileName=/data/local/tmp/${depFileName}
+ adb push ${depJar} ${deviceFileName} &> /dev/null
+ classpath=${classpath}:${deviceFileName}
+ pushedjars=${pushedjars}" "${deviceFileName}
+ done
+
+ adb shell dalvikvm -Djava.io.tmpdir=/data/local/tmp \
+ -classpath $classpath $mainclass >> $datadir/dalvikout 2>&1 && \
+ echo -n dvmpassed: >> $datadir/dalvikout 2>&1
+
+ for jar in ${pushedjars}; do
+ adb shell rm ${jar} &> /dev/null
+ done
+ fi
+
+ echo -n "mk_s:" >> $datadir/dalvikout
+ # Verify tmpout only contains mkdxc_start;mkdxc_stop -> no system.out/err
+ # because of exception. If ok -> green report line else red report with info
+ # between mkdxc_start and stop
+ vmresult=`cat $datadir/dalvikout`
+
+ if [[ ("$vmresult" == "mk_b:mk_s:") || ("$vmresult" == "mk_b:dvmpassed:mk_s:") ]]; then
+ (( jpassedcnt += 1 ))
+ echo -n "<tr class=\"ok\"><td>Success</td><td>$jtitle</td>" >> $report
+ echo "<td>$jcomment</td><td>$details</td></tr>" >> $report
+ echo -n "."
+ else
+ vmres=`cat $datadir/dalvikout | sed -e 's/mk_b://;s/mk_s://'`
+ vmres="$details<br><pre>$vmres</pre>"
+
+ stacktraces=`echo $vmresult | grep "java\.lang\." | grep -c "at dot\.junit\."`
+ if [[ $stacktraces > 0 ]]; then
+ jtype=`echo "$mainclass" | sed -e 's/.*_test\([^0-9]*\)[0-9].*/\1/' `
+ if [ "$jtype" == "VFE" ]; then
+ (( jvfefailedcnt += 1 ))
+ echo -n "V"
+ else
+ (( jfailedcnt += 1 ))
+ echo -n "F"
+ fi
+
+ echo "<tr class=\"nok\"><td>Failure</td><td>$jtitle</td><td>" >> $report
+ echo "$jcomment</td><td>$vmres</td></tr>" >> $report
+ else
+ (( jwarningcnt += 1 ))
+ echo "<tr class=\"wok\"><td>Failure</td><td>$jtitle</td><td>" >> $report
+ echo "$jcomment</td><td>(No stacktrace, but errors on console)" >> $report
+ echo "<br>$vmres</td></tr>" >> $report
+ echo -n "C"
+ fi
+ fi
+
+ (( jcolumns += 1 ))
+ if [ ${jcolumns} -eq 40 ]; then
+ echo ""
+ (( jcolumns = 0 ))
+ fi
+
+ fi
+# Use fd nr 3 to avoid subshelling via cat since this looses all
+# variables(and thus also the counters we are interested in).
+done 3<$scriptdata
+
+echo "</table>" >> $report
+let jallcalccnt=$jpassedcnt+$jfailedcnt+$jvfefailedcnt+$jwarningcnt
+if [ $jallcalccnt -ne $jallcnt ]; then
+ echo "<br>error: green & red != total , $jallcalccnt -ne $jallcnt" >> $report
+ exit 1;
+fi
+
+echo $post_report >> $report
+
+echo "<br>Tests run: ${jallcnt}" >> $report
+echo "<br>Functional failures: ${jfailedcnt}" >> $report
+echo "<br>Verifier failures: ${jvfefailedcnt}" >> $report
+echo "<br>Console errors: ${jwarningcnt}" >> $report
+
+echo $post_report >> $report
+
+if [[ jcolumns -ne 0 ]]; then
+ echo ""
+fi
+
+echo ""
+
+if [[ jallcnt -eq jpassedcnt ]]; then
+ echo "OK (${jpassedcnt} tests)"
+else
+ echo "FAILURES!!!"
+ echo ""
+ echo "Tests run : ${jallcnt}"
+ echo "Functional failures: ${jfailedcnt}"
+ echo "Verifier failures : ${jvfefailedcnt}"
+ echo "Console errors : ${jwarningcnt}"
+fi
+
+echo ""
+echo "Please see complete report in ${report}"
+echo "--------------------------------------------------"
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/invoke_virtual/d/T_invoke_virtual_12.d b/tools/vm-tests-tf/src/dot/junit/opcodes/invoke_virtual/d/T_invoke_virtual_12.d
index 02d509a..8068732 100644
--- a/tools/vm-tests-tf/src/dot/junit/opcodes/invoke_virtual/d/T_invoke_virtual_12.d
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/invoke_virtual/d/T_invoke_virtual_12.d
@@ -25,6 +25,7 @@
.end method
.method public test(Ljava/lang/String;)V
+.limit regs 2
return-void
.end method
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/invoke_virtual_range/d/T_invoke_virtual_range_12.d b/tools/vm-tests-tf/src/dot/junit/opcodes/invoke_virtual_range/d/T_invoke_virtual_range_12.d
index 9b63ef8..93df0f5 100644
--- a/tools/vm-tests-tf/src/dot/junit/opcodes/invoke_virtual_range/d/T_invoke_virtual_range_12.d
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/invoke_virtual_range/d/T_invoke_virtual_range_12.d
@@ -25,6 +25,7 @@
.end method
.method public test(Ljava/lang/String;)V
+.limit regs 2
return-void
.end method
diff --git a/tools/vm-tests-tf/src/util/build/BuildDalvikSuite.java b/tools/vm-tests-tf/src/util/build/BuildDalvikSuite.java
index 9d4bbed..d18ff4f 100644
--- a/tools/vm-tests-tf/src/util/build/BuildDalvikSuite.java
+++ b/tools/vm-tests-tf/src/util/build/BuildDalvikSuite.java
@@ -260,6 +260,7 @@
private void handleTests() throws IOException {
System.out.println("collected " + testMethodsCnt + " test methods in " +
testClassCnt + " junit test classes");
+ String datafileContent = "";
Set<BuildStep> targets = new TreeSet<BuildStep>();
javacHostJunitBuildStep = new JavacBuildStep(HOSTJUNIT_CLASSES_OUTPUT_FOLDER, CLASS_PATH);
@@ -336,6 +337,86 @@
targets.add(dexBuildStep);
// }
+
+ // prepare the entry in the data file for the bash script.
+ // e.g.
+ // main class to execute; opcode/constraint; test purpose
+ // dxc.junit.opcodes.aaload.Main_testN1;aaload;normal case test
+ // (#1)
+
+ char ca = method.charAt("test".length()); // either N,B,E,
+ // or V (VFE)
+ String comment;
+ switch (ca) {
+ case 'N':
+ comment = "Normal #" + method.substring(5);
+ break;
+ case 'B':
+ comment = "Boundary #" + method.substring(5);
+ break;
+ case 'E':
+ comment = "Exception #" + method.substring(5);
+ break;
+ case 'V':
+ comment = "Verifier #" + method.substring(7);
+ break;
+ default:
+ throw new RuntimeException("unknown test abbreviation:"
+ + method + " for " + fqcn);
+ }
+
+ String line = pName + ".Main_" + method + ";";
+ for (String className : dependentTestClassNames) {
+ line += className + " ";
+ }
+
+
+ // test description
+ String[] pparts = pName.split("\\.");
+ // detail e.g. add_double
+ String detail = pparts[pparts.length-1];
+ // type := opcode | verify
+ String type = pparts[pparts.length-2];
+
+ String description;
+ if ("format".equals(type)) {
+ description = "format";
+ } else if ("opcodes".equals(type)) {
+ // Beautify name, so it matches the actual mnemonic
+ detail = detail.replaceAll("_", "-");
+ detail = detail.replace("-from16", "/from16");
+ detail = detail.replace("-high16", "/high16");
+ detail = detail.replace("-lit8", "/lit8");
+ detail = detail.replace("-lit16", "/lit16");
+ detail = detail.replace("-4", "/4");
+ detail = detail.replace("-16", "/16");
+ detail = detail.replace("-32", "/32");
+ detail = detail.replace("-jumbo", "/jumbo");
+ detail = detail.replace("-range", "/range");
+ detail = detail.replace("-2addr", "/2addr");
+
+ // Unescape reserved words
+ detail = detail.replace("opc-", "");
+
+ description = detail;
+ } else if ("verify".equals(type)) {
+ description = "verifier";
+ } else {
+ description = type + " " + detail;
+ }
+
+ String details = (md.title != null ? md.title : "");
+ if (md.constraint != null) {
+ details = " Constraint " + md.constraint + ", " + details;
+ }
+ if (details.length() != 0) {
+ details = details.substring(0, 1).toUpperCase()
+ + details.substring(1);
+ }
+
+ line += ";" + description + ";" + comment + ";" + details;
+
+ datafileContent += line + "\n";
generateBuildStepFor(pName, method, dependentTestClassNames,
targets);
}
@@ -346,6 +427,10 @@
// write latest HOSTJUNIT generated file.
flushHostJunitFile();
+ File scriptDataDir = new File(OUTPUT_FOLDER + "/data/");
+ scriptDataDir.mkdirs();
+ writeToFile(new File(scriptDataDir, "scriptdata"), datafileContent);
+
if (!javacHostJunitBuildStep.build()) {
System.out.println("main javac cts-host-hostjunit-classes build step failed");
System.exit(1);