am 06100c10: am 48cd1128: Merge "Remove Profile Annotations Experiment" into froyo
* commit '06100c103db258ec8b46f2c815c32d337d45367e':
Remove Profile Annotations Experiment
diff --git a/.gitignore b/.gitignore
index 542ab17..ca65e7d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
*.pyc
*.~*
+bin
diff --git a/tests/ProcessTest/Android.mk b/tests/ProcessTest/Android.mk
index be1e7de..ba58e87 100644
--- a/tests/ProcessTest/Android.mk
+++ b/tests/ProcessTest/Android.mk
@@ -20,7 +20,7 @@
# and when built explicitly put it in the data partition
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_JAVA_LIBRARIES := framework-tests android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_AAPT_FLAGS = -c xx_YY -c cs
diff --git a/tests/appsecurity-tests/Android.mk b/tests/appsecurity-tests/Android.mk
index a0f7f41..4ec9922 100644
--- a/tests/appsecurity-tests/Android.mk
+++ b/tests/appsecurity-tests/Android.mk
@@ -23,7 +23,7 @@
LOCAL_MODULE := CtsAppSecurityTests
-LOCAL_JAVA_LIBRARIES := hosttestlib ddmlib junit
+LOCAL_JAVA_LIBRARIES := hosttestlib ddmlib-prebuilt junit
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tests/appsecurity-tests/src/com/android/cts/appsecurity/AppSecurityTests.java b/tests/appsecurity-tests/src/com/android/cts/appsecurity/AppSecurityTests.java
index f528ee1..c0503bc 100644
--- a/tests/appsecurity-tests/src/com/android/cts/appsecurity/AppSecurityTests.java
+++ b/tests/appsecurity-tests/src/com/android/cts/appsecurity/AppSecurityTests.java
@@ -18,10 +18,15 @@
import java.io.File;
import java.io.IOException;
+import java.util.Map;
import junit.framework.Test;
+import com.android.ddmlib.AdbCommandRejectedException;
+import com.android.ddmlib.InstallException;
import com.android.ddmlib.Log;
+import com.android.ddmlib.ShellCommandUnresponsiveException;
+import com.android.ddmlib.TimeoutException;
import com.android.ddmlib.testrunner.ITestRunListener;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
import com.android.ddmlib.testrunner.TestIdentifier;
@@ -78,7 +83,7 @@
* Test that an app that declares the same shared uid as an existing app, cannot be installed
* if it is signed with a different certificate.
*/
- public void testSharedUidDifferentCerts() throws IOException {
+ public void testSharedUidDifferentCerts() throws InstallException {
Log.i(LOG_TAG, "installing apks with shared uid, but different certs");
try {
// cleanup test apps that might be installed from previous partial test run
@@ -104,7 +109,7 @@
* Test that an app update cannot be installed over an existing app if it has a different
* certificate.
*/
- public void testAppUpgradeDifferentCerts() throws IOException {
+ public void testAppUpgradeDifferentCerts() throws InstallException {
Log.i(LOG_TAG, "installing app upgrade with different certs");
try {
// cleanup test app that might be installed from previous partial test run
@@ -127,7 +132,8 @@
/**
* Test that an app cannot access another app's private data.
*/
- public void testAppFailAccessPrivateData() throws IOException {
+ public void testAppFailAccessPrivateData() throws InstallException, TimeoutException,
+ AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException {
Log.i(LOG_TAG, "installing app that attempts to access another app's private data");
try {
// cleanup test app that might be installed from previous partial test run
@@ -155,7 +161,8 @@
/**
* Test that an app cannot instrument another app that is signed with different certificate.
*/
- public void testInstrumentationDiffCert() throws IOException {
+ public void testInstrumentationDiffCert() throws InstallException, TimeoutException,
+ AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException {
Log.i(LOG_TAG, "installing app that attempts to instrument another app");
try {
// cleanup test app that might be installed from previous partial test run
@@ -186,7 +193,8 @@
* Test that an app cannot use a signature-enforced permission if it is signed with a different
* certificate than the app that declared the permission.
*/
- public void testPermissionDiffCert() throws IOException {
+ public void testPermissionDiffCert() throws InstallException, TimeoutException,
+ AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException {
Log.i(LOG_TAG, "installing app that attempts to use permission of another app");
try {
// cleanup test app that might be installed from previous partial test run
@@ -225,8 +233,15 @@
*
* @param pkgName Android application package for tests
* @return <code>true</code> if all tests passed.
+ * @throws TimeoutException in case of a timeout on the connection.
+ * @throws AdbCommandRejectedException if adb rejects the command
+ * @throws ShellCommandUnresponsiveException if the device did not output any test result for
+ * a period longer than the max time to output.
+ * @throws IOException if connection to device was lost.
*/
- private boolean runDeviceTests(String pkgName) {
+ private boolean runDeviceTests(String pkgName)
+ throws TimeoutException, AdbCommandRejectedException,
+ ShellCommandUnresponsiveException, IOException {
CollectingTestRunListener listener = doRunTests(pkgName);
return listener.didAllTestsPass();
}
@@ -235,20 +250,40 @@
* Helper method to run tests and return the listener that collected the results.
* @param pkgName Android application package for tests
* @return the {@link CollectingTestRunListener}
+ * @throws TimeoutException in case of a timeout on the connection.
+ * @throws AdbCommandRejectedException if adb rejects the command
+ * @throws ShellCommandUnresponsiveException if the device did not output any test result for
+ * a period longer than the max time to output.
+ * @throws IOException if connection to device was lost.
*/
- private CollectingTestRunListener doRunTests(String pkgName) {
+ private CollectingTestRunListener doRunTests(String pkgName)
+ throws TimeoutException, AdbCommandRejectedException,
+ ShellCommandUnresponsiveException, IOException {
RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(pkgName, getDevice());
CollectingTestRunListener listener = new CollectingTestRunListener();
testRunner.run(listener);
return listener;
}
+ /**
+ * Helper method to run the specified packages tests, and return the test run error message.
+ *
+ * @param pkgName Android application package for tests
+ * @return the test run error message or <code>null</code> if test run completed.
+ * @throws IOException if connection to device was lost
+ */
+ private String runDeviceTestsWithRunResult(String pkgName) throws TimeoutException,
+ AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException {
+ CollectingTestRunListener listener = doRunTests(pkgName);
+ return listener.getTestRunErrorMessage();
+ }
+
private static class CollectingTestRunListener implements ITestRunListener {
private boolean mAllTestsPassed = true;
private String mTestRunErrorMessage = null;
- public void testEnded(TestIdentifier test) {
+ public void testEnded(TestIdentifier test, Map<String, String> metrics) {
// ignore
}
@@ -259,7 +294,7 @@
mAllTestsPassed = false;
}
- public void testRunEnded(long elapsedTime) {
+ public void testRunEnded(long elapsedTime, Map<String, String> resultBundle) {
// ignore
}
@@ -269,7 +304,7 @@
mTestRunErrorMessage = errorMessage;
}
- public void testRunStarted(int testCount) {
+ public void testRunStarted(String runName, int testCount) {
// ignore
}
diff --git a/tests/appsecurity-tests/test-apps/PermissionDeclareApp/AndroidManifest.xml b/tests/appsecurity-tests/test-apps/PermissionDeclareApp/AndroidManifest.xml
index 53ab2cf..683ec9e 100644
--- a/tests/appsecurity-tests/test-apps/PermissionDeclareApp/AndroidManifest.xml
+++ b/tests/appsecurity-tests/test-apps/PermissionDeclareApp/AndroidManifest.xml
@@ -20,16 +20,66 @@
An app that declares a permission that requires a matching signature to
access.
-->
-
<permission android:name="com.android.cts.permissionWithSignature"
android:protectionLevel="signature" />
+ <uses-permission android:name="com.android.cts.permissionWithSignature" />
+
+ <!-- A permission this app will not hold. -->
+ <permission android:name="com.android.cts.permissionNotUsedWithSignature"
+ android:protectionLevel="signature" />
<application>
+ <receiver android:name="GrantUriPermission" android:exported="true">
+ </receiver>
+
<!-- Need a way for another app to try to access the permission. So create a content
provider which is enforced by the permission -->
<provider android:name="PermissionContentProvider"
android:authorities="ctspermissionwithsignature"
android:readPermission="com.android.cts.permissionWithSignature"
- android:writePermission="com.android.cts.permissionWithSignature" />
+ android:writePermission="com.android.cts.permissionWithSignature">
+ </provider>
+
+ <!-- Need a way for another app to try to access the permission, but will
+ grant uri access. -->
+ <provider android:name="PermissionContentProviderGranting"
+ android:authorities="ctspermissionwithsignaturegranting"
+ android:readPermission="com.android.cts.permissionWithSignature"
+ android:writePermission="com.android.cts.permissionWithSignature">
+ <grant-uri-permission android:pathPattern="/foo.*" />
+ <grant-uri-permission android:pathPattern="/yes.*" />
+ </provider>
+
+ <!-- Nobody else should get access to this -->
+ <provider android:name="PrivateContentProvider"
+ android:authorities="ctsprivateprovider"
+ android:exported="false">
+ </provider>
+
+ <!-- Nobody else should get access to this, but we will grant uri access -->
+ <provider android:name="PrivateContentProviderGranting"
+ android:authorities="ctsprivateprovidergranting"
+ android:exported="false">
+ <grant-uri-permission android:pathPattern="/foo.*" />
+ <grant-uri-permission android:pathPattern="/yes.*" />
+ </provider>
+
+ <!-- Target for tests about how path permissions interact with granting
+ URI permissions. -->
+ <provider android:name="PermissionContentProviderPath"
+ android:authorities="ctspermissionwithsignaturepath"
+ android:readPermission="com.android.cts.permissionNotUsedWithSignature"
+ android:writePermission="com.android.cts.permissionNotUsedWithSignature">
+ <path-permission
+ android:pathPrefix="/foo"
+ android:readPermission="com.android.cts.permissionWithSignature"
+ android:writePermission="com.android.cts.permissionWithSignature" />
+ <path-permission
+ android:pathPrefix="/yes"
+ android:readPermission="com.android.cts.permissionWithSignature"
+ android:writePermission="com.android.cts.permissionWithSignature" />
+ <grant-uri-permission android:pathPattern=".*" />
+ </provider>
+
</application>
</manifest>
diff --git a/tests/appsecurity-tests/test-apps/PermissionDeclareApp/src/com/android/cts/permissiondeclareapp/GrantUriPermission.java b/tests/appsecurity-tests/test-apps/PermissionDeclareApp/src/com/android/cts/permissiondeclareapp/GrantUriPermission.java
new file mode 100644
index 0000000..8c14575
--- /dev/null
+++ b/tests/appsecurity-tests/test-apps/PermissionDeclareApp/src/com/android/cts/permissiondeclareapp/GrantUriPermission.java
@@ -0,0 +1,30 @@
+package com.android.cts.permissiondeclareapp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+public class GrantUriPermission extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Intent newIntent = (Intent)intent.getParcelableExtra("intent");
+ boolean service = intent.getBooleanExtra("service", false);
+ try {
+ if (!service) {
+ newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(newIntent);
+ } else {
+ context.startService(newIntent);
+ }
+ if (isOrderedBroadcast()) {
+ setResultCode(101);
+ }
+ } catch (SecurityException e) {
+ Log.i("GrantUriPermission", "Security exception", e);
+ if (isOrderedBroadcast()) {
+ setResultCode(100);
+ }
+ }
+ }
+}
diff --git a/tests/appsecurity-tests/test-apps/PermissionDeclareApp/src/com/android/cts/permissiondeclareapp/PermissionContentProvider.java b/tests/appsecurity-tests/test-apps/PermissionDeclareApp/src/com/android/cts/permissiondeclareapp/PermissionContentProvider.java
index e68bb1b..900664f 100644
--- a/tests/appsecurity-tests/test-apps/PermissionDeclareApp/src/com/android/cts/permissiondeclareapp/PermissionContentProvider.java
+++ b/tests/appsecurity-tests/test-apps/PermissionDeclareApp/src/com/android/cts/permissiondeclareapp/PermissionContentProvider.java
@@ -34,7 +34,7 @@
@Override
public String getType(Uri uri) {
- return null;
+ return "got/theMIME";
}
@Override
diff --git a/tests/appsecurity-tests/test-apps/PermissionDeclareApp/src/com/android/cts/permissiondeclareapp/PermissionContentProviderGranting.java b/tests/appsecurity-tests/test-apps/PermissionDeclareApp/src/com/android/cts/permissiondeclareapp/PermissionContentProviderGranting.java
new file mode 100644
index 0000000..97bd827
--- /dev/null
+++ b/tests/appsecurity-tests/test-apps/PermissionDeclareApp/src/com/android/cts/permissiondeclareapp/PermissionContentProviderGranting.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2009 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.permissiondeclareapp;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+/**
+ * Empty content provider, all permissions are enforced in manifest
+ */
+public class PermissionContentProviderGranting extends ContentProvider {
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ // do nothing
+ return 0;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return "got/theMIME";
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public boolean onCreate() {
+ return false;
+ }
+
+ @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;
+ }
+}
diff --git a/tests/appsecurity-tests/test-apps/PermissionDeclareApp/src/com/android/cts/permissiondeclareapp/PermissionContentProviderPath.java b/tests/appsecurity-tests/test-apps/PermissionDeclareApp/src/com/android/cts/permissiondeclareapp/PermissionContentProviderPath.java
new file mode 100644
index 0000000..4f301a3
--- /dev/null
+++ b/tests/appsecurity-tests/test-apps/PermissionDeclareApp/src/com/android/cts/permissiondeclareapp/PermissionContentProviderPath.java
@@ -0,0 +1,45 @@
+package com.android.cts.permissiondeclareapp;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+/**
+ * Empty content provider, all permissions are enforced in manifest
+ */
+public class PermissionContentProviderPath extends ContentProvider {
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ // do nothing
+ return 0;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return "got/theMIME";
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public boolean onCreate() {
+ return false;
+ }
+
+ @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;
+ }
+}
diff --git a/tests/appsecurity-tests/test-apps/PermissionDeclareApp/src/com/android/cts/permissiondeclareapp/PrivateContentProvider.java b/tests/appsecurity-tests/test-apps/PermissionDeclareApp/src/com/android/cts/permissiondeclareapp/PrivateContentProvider.java
new file mode 100644
index 0000000..64ec6e7
--- /dev/null
+++ b/tests/appsecurity-tests/test-apps/PermissionDeclareApp/src/com/android/cts/permissiondeclareapp/PrivateContentProvider.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2009 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.permissiondeclareapp;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+/**
+ * Empty content provider, all permissions are enforced in manifest
+ */
+public class PrivateContentProvider extends ContentProvider {
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ // do nothing
+ return 0;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return "got/theMIME";
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public boolean onCreate() {
+ return false;
+ }
+
+ @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;
+ }
+}
diff --git a/tests/appsecurity-tests/test-apps/PermissionDeclareApp/src/com/android/cts/permissiondeclareapp/PrivateContentProviderGranting.java b/tests/appsecurity-tests/test-apps/PermissionDeclareApp/src/com/android/cts/permissiondeclareapp/PrivateContentProviderGranting.java
new file mode 100644
index 0000000..f9ae96b
--- /dev/null
+++ b/tests/appsecurity-tests/test-apps/PermissionDeclareApp/src/com/android/cts/permissiondeclareapp/PrivateContentProviderGranting.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2009 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.permissiondeclareapp;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+/**
+ * Empty content provider, all permissions are enforced in manifest
+ */
+public class PrivateContentProviderGranting extends ContentProvider {
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ // do nothing
+ return 0;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return "got/theMIME";
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public boolean onCreate() {
+ return false;
+ }
+
+ @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;
+ }
+}
diff --git a/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/AndroidManifest.xml b/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/AndroidManifest.xml
index b915ebc..e01bc90 100644
--- a/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/AndroidManifest.xml
+++ b/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/AndroidManifest.xml
@@ -17,14 +17,21 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cts.usespermissiondiffcertapp">
- <!--
- This app declares it uses a permission that requires same signature as app that declares it.
- -->
-
+ <!-- We say we want to use the other app's permission, but it is signed with
+ a different cert so it should fail. -->
<uses-permission android:name="com.android.cts.permissionWithSignature"/>
+ <!-- This is a permission we can have, which the other app can require for
+ access. -->
+ <permission android:name="com.android.cts.permissionAllowedWithSignature"
+ android:protectionLevel="signature" />
+ <uses-permission android:name="com.android.cts.permissionAllowedWithSignature"/>
+
<application>
<uses-library android:name="android.test.runner"/>
+ <activity android:name=".ReceiveUriActivity" android:exported="true"
+ android:launchMode="singleTop" />
+ <service android:name=".ReceiveUriService" android:exported="true" />
</application>
<instrumentation android:targetPackage="com.android.cts.usespermissiondiffcertapp"
diff --git a/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java b/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
index 510d5e4..63a65e4 100644
--- a/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
+++ b/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
@@ -16,21 +16,809 @@
package com.android.cts.usespermissiondiffcertapp;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
import android.net.Uri;
+import android.os.SystemClock;
import android.test.AndroidTestCase;
+import android.util.Log;
/**
* Tests that signature-enforced permissions cannot be accessed by apps signed
* with different certs than app that declares the permission.
+ *
+ * Accesses app cts/tests/appsecurity-tests/test-apps/PermissionDeclareApp/...
*/
public class AccessPermissionWithDiffSigTest extends AndroidTestCase {
+ static final ComponentName GRANT_URI_PERM_COMP
+ = new ComponentName("com.android.cts.permissiondeclareapp",
+ "com.android.cts.permissiondeclareapp.GrantUriPermission");
+ static final Uri PERM_URI = Uri.parse("content://ctspermissionwithsignature");
+ static final Uri PERM_URI_GRANTING = Uri.parse("content://ctspermissionwithsignaturegranting");
+ static final Uri PERM_URI_PATH = Uri.parse("content://ctspermissionwithsignaturepath");
+ static final Uri PRIV_URI = Uri.parse("content://ctsprivateprovider");
+ static final Uri PRIV_URI_GRANTING = Uri.parse("content://ctsprivateprovidergranting");
+
+ static final String EXPECTED_MIME_TYPE = "got/theMIME";
+
+ public void assertReadingContentUriNotAllowed(Uri uri, String msg) {
+ try {
+ getContext().getContentResolver().query(uri, null, null, null, null);
+ fail("expected SecurityException reading " + uri + ": " + msg);
+ } catch (SecurityException expected) {
+ assertNotNull("security exception's error message.", expected.getMessage());
+ }
+ }
+
+ public void assertWritingContentUriNotAllowed(Uri uri, String msg) {
+ try {
+ getContext().getContentResolver().insert(uri, new ContentValues());
+ fail("expected SecurityException writing " + uri + ": " + msg);
+ } catch (SecurityException expected) {
+ assertNotNull("security exception's error message.", expected.getMessage());
+ }
+ }
/**
* Test that the ctspermissionwithsignature content provider cannot be read,
* since this app lacks the required certs
*/
public void testReadProviderWithDiff() {
- assertReadingContentUriRequiresPermission(Uri.parse("content://ctspermissionwithsignature"),
+ assertReadingContentUriRequiresPermission(PERM_URI,
"com.android.cts.permissionWithSignature");
}
+
+ /**
+ * Test that the ctspermissionwithsignature content provider cannot be written,
+ * since this app lacks the required certs
+ */
+ public void testWriteProviderWithDiff() {
+ assertWritingContentUriRequiresPermission(PERM_URI,
+ "com.android.cts.permissionWithSignature");
+ }
+
+ /**
+ * Test that the ctsprivateprovider content provider cannot be read,
+ * since it is not exported from its app.
+ */
+ public void testReadProviderWhenPrivate() {
+ assertReadingContentUriNotAllowed(PRIV_URI,
+ "shouldn't read private provider");
+ }
+
+ /**
+ * Test that the ctsprivateprovider content provider cannot be written,
+ * since it is not exported from its app.
+ */
+ public void testWriteProviderWhenPrivate() {
+ assertWritingContentUriNotAllowed(PRIV_URI,
+ "shouldn't write private provider");
+ }
+
+ public void doTryGrantUriActivityPermissionToSelf(Uri uri, int mode) {
+ Intent grantIntent = new Intent();
+ grantIntent.setData(uri);
+ grantIntent.addFlags(mode | Intent.FLAG_ACTIVITY_NEW_TASK);
+ grantIntent.setClass(getContext(), ReceiveUriActivity.class);
+ try {
+ ReceiveUriActivity.clearStarted();
+ getContext().startActivity(grantIntent);
+ ReceiveUriActivity.waitForStart();
+ fail("expected SecurityException granting " + uri + " to activity");
+ } catch (SecurityException e) {
+ // This is what we want.
+ }
+ }
+
+ /**
+ * Test that we can't grant a permission to ourself.
+ */
+ public void testGrantReadUriActivityPermissionToSelf() {
+ doTryGrantUriActivityPermissionToSelf(
+ Uri.withAppendedPath(PERM_URI_GRANTING, "foo"),
+ Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
+
+ /**
+ * Test that we can't grant a permission to ourself.
+ */
+ public void testGrantWriteUriActivityPermissionToSelf() {
+ doTryGrantUriActivityPermissionToSelf(
+ Uri.withAppendedPath(PERM_URI_GRANTING, "foo"),
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ }
+
+ /**
+ * Test that we can't grant a permission to ourself.
+ */
+ public void testGrantReadUriActivityPrivateToSelf() {
+ doTryGrantUriActivityPermissionToSelf(
+ Uri.withAppendedPath(PRIV_URI_GRANTING, "foo"),
+ Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
+
+ /**
+ * Test that we can't grant a permission to ourself.
+ */
+ public void testGrantWriteUriActivityPrivateToSelf() {
+ doTryGrantUriActivityPermissionToSelf(
+ Uri.withAppendedPath(PRIV_URI_GRANTING, "foo"),
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ }
+
+ public void doTryGrantUriServicePermissionToSelf(Uri uri, int mode) {
+ Intent grantIntent = new Intent();
+ grantIntent.setData(uri);
+ grantIntent.addFlags(mode);
+ grantIntent.setClass(getContext(), ReceiveUriService.class);
+ try {
+ getContext().startService(grantIntent);
+ fail("expected SecurityException granting " + uri + " to service");
+ } catch (SecurityException e) {
+ // This is what we want.
+ }
+ }
+
+ /**
+ * Test that we can't grant a permission to ourself.
+ */
+ public void testGrantReadUriServicePermissionToSelf() {
+ doTryGrantUriServicePermissionToSelf(
+ Uri.withAppendedPath(PERM_URI_GRANTING, "foo"),
+ Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
+
+ /**
+ * Test that we can't grant a permission to ourself.
+ */
+ public void testGrantWriteUriServicePermissionToSelf() {
+ doTryGrantUriServicePermissionToSelf(
+ Uri.withAppendedPath(PERM_URI_GRANTING, "foo"),
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ }
+
+ /**
+ * Test that we can't grant a permission to ourself.
+ */
+ public void testGrantReadUriServicePrivateToSelf() {
+ doTryGrantUriServicePermissionToSelf(
+ Uri.withAppendedPath(PRIV_URI_GRANTING, "foo"),
+ Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
+
+ /**
+ * Test that we can't grant a permission to ourself.
+ */
+ public void testGrantWriteUriServicePrivateToSelf() {
+ doTryGrantUriServicePermissionToSelf(
+ Uri.withAppendedPath(PRIV_URI_GRANTING, "foo"),
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ }
+
+ static class GrantResultReceiver extends BroadcastReceiver {
+ boolean mHaveResult = false;
+ boolean mGoodResult = false;
+ boolean mSucceeded = false;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ synchronized (this) {
+ mHaveResult = true;
+ switch (getResultCode()) {
+ case 100:
+ mGoodResult = true;
+ mSucceeded = false;
+ break;
+ case 101:
+ mGoodResult = true;
+ mSucceeded = true;
+ break;
+ default:
+ mGoodResult = false;
+ break;
+ }
+ notifyAll();
+ }
+ }
+
+ void assertSuccess(String failureMessage) {
+ synchronized (this) {
+ final long startTime = SystemClock.uptimeMillis();
+ while (!mHaveResult) {
+ try {
+ wait(5000);
+ } catch (InterruptedException e) {
+ }
+ if (SystemClock.uptimeMillis() >= (startTime+5000)) {
+ throw new RuntimeException("Timeout");
+ }
+ }
+ if (!mGoodResult) {
+ fail("Broadcast receiver did not return good result");
+ }
+ if (!mSucceeded) {
+ fail(failureMessage);
+ }
+ }
+ }
+
+ void assertFailure(String failureMessage) {
+ synchronized (this) {
+ final long startTime = SystemClock.uptimeMillis();
+ while (!mHaveResult) {
+ try {
+ wait(5000);
+ } catch (InterruptedException e) {
+ }
+ if (SystemClock.uptimeMillis() >= (startTime+5000)) {
+ throw new RuntimeException("Timeout");
+ }
+ }
+ if (!mGoodResult) {
+ fail("Broadcast receiver did not return good result");
+ }
+ if (mSucceeded) {
+ fail(failureMessage);
+ }
+ }
+ }
+ }
+
+ void grantUriPermissionFail(Uri uri, int mode, boolean service) {
+ Intent grantIntent = new Intent();
+ grantIntent.setData(uri);
+ grantIntent.addFlags(mode);
+ grantIntent.setClass(getContext(),
+ service ? ReceiveUriService.class : ReceiveUriActivity.class);
+ Intent intent = new Intent();
+ intent.setComponent(GRANT_URI_PERM_COMP);
+ intent.putExtra("intent", grantIntent);
+ intent.putExtra("service", service);
+ GrantResultReceiver receiver = new GrantResultReceiver();
+ getContext().sendOrderedBroadcast(intent, null, receiver, null, 0, null, null);
+ receiver.assertFailure("Able to grant URI permission to " + uri + " when should not");
+ }
+
+ void doTestGrantUriPermissionFail(Uri uri) {
+ grantUriPermissionFail(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, false);
+ grantUriPermissionFail(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, false);
+ grantUriPermissionFail(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, true);
+ grantUriPermissionFail(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true);
+ }
+
+ /**
+ * Test that the ctspermissionwithsignature content provider can not grant
+ * URI permissions to others.
+ */
+ public void testGrantPermissionNonGrantingFail() {
+ doTestGrantUriPermissionFail(PERM_URI);
+ }
+
+ /**
+ * Test that the ctspermissionwithsignaturegranting content provider can not grant
+ * URI permissions to paths outside of the grant tree
+ */
+ public void testGrantPermissionOutsideGrantingFail() {
+ doTestGrantUriPermissionFail(PERM_URI_GRANTING);
+ doTestGrantUriPermissionFail(Uri.withAppendedPath(PERM_URI_GRANTING, "invalid"));
+ }
+
+ /**
+ * Test that the ctsprivateprovider content provider can not grant
+ * URI permissions to others.
+ */
+ public void testGrantPrivateNonGrantingFail() {
+ doTestGrantUriPermissionFail(PRIV_URI);
+ }
+
+ /**
+ * Test that the ctsprivateprovidergranting content provider can not grant
+ * URI permissions to paths outside of the grant tree
+ */
+ public void testGrantPrivateOutsideGrantingFail() {
+ doTestGrantUriPermissionFail(PRIV_URI_GRANTING);
+ doTestGrantUriPermissionFail(Uri.withAppendedPath(PRIV_URI_GRANTING, "invalid"));
+ }
+
+ void grantUriPermission(Uri uri, int mode, boolean service) {
+ Intent grantIntent = new Intent();
+ grantIntent.setData(uri);
+ grantIntent.addFlags(mode);
+ grantIntent.setClass(getContext(),
+ service ? ReceiveUriService.class : ReceiveUriActivity.class);
+ Intent intent = new Intent();
+ intent.setComponent(GRANT_URI_PERM_COMP);
+ intent.putExtra("intent", grantIntent);
+ intent.putExtra("service", service);
+ getContext().sendBroadcast(intent);
+ }
+
+ void doTestGrantActivityUriReadPermission(Uri uri) {
+ final Uri subUri = Uri.withAppendedPath(uri, "foo");
+ final Uri subSubUri = Uri.withAppendedPath(subUri, "bar");
+ final Uri sub2Uri = Uri.withAppendedPath(uri, "yes");
+ final Uri sub2SubUri = Uri.withAppendedPath(sub2Uri, "no");
+
+ // Precondition: no current access.
+ assertReadingContentUriNotAllowed(subUri, "shouldn't read when starting test");
+ assertReadingContentUriNotAllowed(sub2Uri, "shouldn't read when starting test");
+
+ // --------------------------------
+
+ ReceiveUriActivity.clearStarted();
+ grantUriPermission(subUri, Intent.FLAG_GRANT_READ_URI_PERMISSION, false);
+ ReceiveUriActivity.waitForStart();
+
+ // See if we now have access to the provider.
+ getContext().getContentResolver().query(subUri, null, null, null, null);
+
+ // But not writing.
+ assertWritingContentUriNotAllowed(subUri, "shouldn't write from granted read");
+
+ // And not to the base path.
+ assertReadingContentUriNotAllowed(uri, "shouldn't read non-granted base URI");
+
+ // And not to a sub path.
+ assertReadingContentUriNotAllowed(subSubUri, "shouldn't read non-granted sub URI");
+
+ // --------------------------------
+
+ ReceiveUriActivity.clearNewIntent();
+ grantUriPermission(sub2Uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, false);
+ ReceiveUriActivity.waitForNewIntent();
+
+ if (false) {
+ synchronized (this) {
+ Log.i("**", "******************************* WAITING!!!");
+ try {
+ wait(10000);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ // See if we now have access to the provider.
+ getContext().getContentResolver().query(sub2Uri, null, null, null, null);
+
+ // And still have access to the original URI.
+ getContext().getContentResolver().query(subUri, null, null, null, null);
+
+ // But not writing.
+ assertWritingContentUriNotAllowed(sub2Uri, "shouldn't write from granted read");
+
+ // And not to the base path.
+ assertReadingContentUriNotAllowed(uri, "shouldn't read non-granted base URI");
+
+ // And not to a sub path.
+ assertReadingContentUriNotAllowed(sub2SubUri, "shouldn't read non-granted sub URI");
+
+ // And make sure we can't generate a permission to a running activity.
+ doTryGrantUriActivityPermissionToSelf(
+ Uri.withAppendedPath(uri, "hah"),
+ Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ doTryGrantUriActivityPermissionToSelf(
+ Uri.withAppendedPath(uri, "hah"),
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
+ // --------------------------------
+
+ // Dispose of activity.
+ ReceiveUriActivity.finishCurInstanceSync();
+
+ if (false) {
+ synchronized (this) {
+ Log.i("**", "******************************* WAITING!!!");
+ try {
+ wait(10000);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ // Ensure reading no longer allowed.
+ assertReadingContentUriNotAllowed(subUri, "shouldn't read after losing granted URI");
+ assertReadingContentUriNotAllowed(sub2Uri, "shouldn't read after losing granted URI");
+ }
+
+ void doTestGrantActivityUriWritePermission(Uri uri) {
+ final Uri subUri = Uri.withAppendedPath(uri, "foo");
+ final Uri subSubUri = Uri.withAppendedPath(subUri, "bar");
+ final Uri sub2Uri = Uri.withAppendedPath(uri, "yes");
+ final Uri sub2SubUri = Uri.withAppendedPath(sub2Uri, "no");
+
+ // Precondition: no current access.
+ assertWritingContentUriNotAllowed(subUri, "shouldn't write when starting test");
+ assertWritingContentUriNotAllowed(sub2Uri, "shouldn't write when starting test");
+
+ // --------------------------------
+
+ ReceiveUriActivity.clearStarted();
+ grantUriPermission(subUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, false);
+ ReceiveUriActivity.waitForStart();
+
+ // See if we now have access to the provider.
+ getContext().getContentResolver().insert(subUri, new ContentValues());
+
+ // But not reading.
+ assertReadingContentUriNotAllowed(subUri, "shouldn't read from granted write");
+
+ // And not to the base path.
+ assertWritingContentUriNotAllowed(uri, "shouldn't write non-granted base URI");
+
+ // And not a sub-path.
+ assertWritingContentUriNotAllowed(subSubUri, "shouldn't write non-granted sub URI");
+
+ // --------------------------------
+
+ ReceiveUriActivity.clearNewIntent();
+ grantUriPermission(sub2Uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, false);
+ ReceiveUriActivity.waitForNewIntent();
+
+ if (false) {
+ synchronized (this) {
+ Log.i("**", "******************************* WAITING!!!");
+ try {
+ wait(10000);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ // See if we now have access to the provider.
+ getContext().getContentResolver().insert(sub2Uri, new ContentValues());
+
+ // And still have access to the original URI.
+ getContext().getContentResolver().insert(subUri, new ContentValues());
+
+ // But not reading.
+ assertReadingContentUriNotAllowed(sub2Uri, "shouldn't read from granted write");
+
+ // And not to the base path.
+ assertWritingContentUriNotAllowed(uri, "shouldn't write non-granted base URI");
+
+ // And not a sub-path.
+ assertWritingContentUriNotAllowed(sub2SubUri, "shouldn't write non-granted sub URI");
+
+ // And make sure we can't generate a permission to a running activity.
+ doTryGrantUriActivityPermissionToSelf(
+ Uri.withAppendedPath(uri, "hah"),
+ Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ doTryGrantUriActivityPermissionToSelf(
+ Uri.withAppendedPath(uri, "hah"),
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
+ // --------------------------------
+
+ // Dispose of activity.
+ ReceiveUriActivity.finishCurInstanceSync();
+
+ if (false) {
+ synchronized (this) {
+ Log.i("**", "******************************* WAITING!!!");
+ try {
+ wait(10000);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ // Ensure writing no longer allowed.
+ assertWritingContentUriNotAllowed(subUri, "shouldn't write after losing granted URI");
+ assertWritingContentUriNotAllowed(sub2Uri, "shouldn't write after losing granted URI");
+ }
+
+ /**
+ * Test that the ctspermissionwithsignaturegranting content provider can grant a read
+ * permission.
+ */
+ public void testGrantReadPermissionFromStartActivity() {
+ doTestGrantActivityUriReadPermission(PERM_URI_GRANTING);
+ }
+
+ /**
+ * Test that the ctspermissionwithsignaturegranting content provider can grant a write
+ * permission.
+ */
+ public void testGrantWritePermissionFromStartActivity() {
+ doTestGrantActivityUriWritePermission(PERM_URI_GRANTING);
+ }
+
+ /**
+ * Test that the ctsprivateprovidergranting content provider can grant a read
+ * permission.
+ */
+ public void testGrantReadPrivateFromStartActivity() {
+ doTestGrantActivityUriReadPermission(PRIV_URI_GRANTING);
+ }
+
+ /**
+ * Test that the ctsprivateprovidergranting content provider can grant a write
+ * permission.
+ */
+ public void testGrantWritePrivateFromStartActivity() {
+ doTestGrantActivityUriWritePermission(PRIV_URI_GRANTING);
+ }
+
+ void doTestGrantServiceUriReadPermission(Uri uri) {
+ final Uri subUri = Uri.withAppendedPath(uri, "foo");
+ final Uri subSubUri = Uri.withAppendedPath(subUri, "bar");
+ final Uri sub2Uri = Uri.withAppendedPath(uri, "yes");
+ final Uri sub2SubUri = Uri.withAppendedPath(sub2Uri, "no");
+
+ ReceiveUriService.stop(getContext());
+
+ // Precondition: no current access.
+ assertReadingContentUriNotAllowed(subUri, "shouldn't read when starting test");
+ assertReadingContentUriNotAllowed(sub2Uri, "shouldn't read when starting test");
+
+ // --------------------------------
+
+ ReceiveUriService.clearStarted();
+ grantUriPermission(subUri, Intent.FLAG_GRANT_READ_URI_PERMISSION, true);
+ ReceiveUriService.waitForStart();
+
+ int firstStartId = ReceiveUriService.getCurStartId();
+
+ // See if we now have access to the provider.
+ getContext().getContentResolver().query(subUri, null, null, null, null);
+
+ // But not writing.
+ assertWritingContentUriNotAllowed(subUri, "shouldn't write from granted read");
+
+ // And not to the base path.
+ assertReadingContentUriNotAllowed(uri, "shouldn't read non-granted base URI");
+
+ // And not to a sub path.
+ assertReadingContentUriNotAllowed(subSubUri, "shouldn't read non-granted sub URI");
+
+ // --------------------------------
+
+ // Send another Intent to it.
+ ReceiveUriService.clearStarted();
+ grantUriPermission(sub2Uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, true);
+ ReceiveUriService.waitForStart();
+
+ if (false) {
+ synchronized (this) {
+ Log.i("**", "******************************* WAITING!!!");
+ try {
+ wait(10000);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ // See if we now have access to the provider.
+ getContext().getContentResolver().query(sub2Uri, null, null, null, null);
+
+ // And still to the previous URI.
+ getContext().getContentResolver().query(subUri, null, null, null, null);
+
+ // But not writing.
+ assertWritingContentUriNotAllowed(sub2Uri, "shouldn't write from granted read");
+
+ // And not to the base path.
+ assertReadingContentUriNotAllowed(uri, "shouldn't read non-granted base URI");
+
+ // And not to a sub path.
+ assertReadingContentUriNotAllowed(sub2SubUri, "shouldn't read non-granted sub URI");
+
+ // --------------------------------
+
+ // Stop the first command.
+ ReceiveUriService.stopCurWithId(firstStartId);
+
+ // Ensure reading no longer allowed.
+ assertReadingContentUriNotAllowed(subUri, "shouldn't read after losing granted URI");
+
+ // And make sure we can't generate a permission to a running service.
+ doTryGrantUriActivityPermissionToSelf(subUri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ doTryGrantUriActivityPermissionToSelf(subUri,
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
+ // --------------------------------
+
+ // Dispose of service.
+ ReceiveUriService.stopSync(getContext());
+
+ // Ensure reading no longer allowed.
+ assertReadingContentUriNotAllowed(subUri, "shouldn't read after losing granted URI");
+ assertReadingContentUriNotAllowed(sub2Uri, "shouldn't read after losing granted URI");
+ }
+
+ void doTestGrantServiceUriWritePermission(Uri uri) {
+ final Uri subUri = Uri.withAppendedPath(uri, "foo");
+ final Uri subSubUri = Uri.withAppendedPath(subUri, "bar");
+ final Uri sub2Uri = Uri.withAppendedPath(uri, "yes");
+ final Uri sub2SubUri = Uri.withAppendedPath(sub2Uri, "no");
+
+ ReceiveUriService.stop(getContext());
+
+ // Precondition: no current access.
+ assertWritingContentUriNotAllowed(subUri, "shouldn't write when starting test");
+ assertWritingContentUriNotAllowed(sub2Uri, "shouldn't write when starting test");
+
+ // --------------------------------
+
+ ReceiveUriService.clearStarted();
+ grantUriPermission(subUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true);
+ ReceiveUriService.waitForStart();
+
+ int firstStartId = ReceiveUriService.getCurStartId();
+
+ // See if we now have access to the provider.
+ getContext().getContentResolver().insert(subUri, new ContentValues());
+
+ // But not reading.
+ assertReadingContentUriNotAllowed(subUri, "shouldn't read from granted write");
+
+ // And not to the base path.
+ assertWritingContentUriNotAllowed(uri, "shouldn't write non-granted base URI");
+
+ // And not a sub-path.
+ assertWritingContentUriNotAllowed(subSubUri, "shouldn't write non-granted sub URI");
+
+ // --------------------------------
+
+ // Send another Intent to it.
+ ReceiveUriService.clearStarted();
+ grantUriPermission(sub2Uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true);
+ ReceiveUriService.waitForStart();
+
+ // See if we now have access to the provider.
+ getContext().getContentResolver().insert(sub2Uri, new ContentValues());
+
+ // And still to the previous URI.
+ getContext().getContentResolver().insert(subUri, new ContentValues());
+
+ // But not reading.
+ assertReadingContentUriNotAllowed(sub2Uri, "shouldn't read from granted write");
+
+ // And not to the base path.
+ assertWritingContentUriNotAllowed(uri, "shouldn't write non-granted base URI");
+
+ // And not a sub-path.
+ assertWritingContentUriNotAllowed(sub2SubUri, "shouldn't write non-granted sub URI");
+
+ if (false) {
+ synchronized (this) {
+ Log.i("**", "******************************* WAITING!!!");
+ try {
+ wait(10000);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ // --------------------------------
+
+ // Stop the first command.
+ ReceiveUriService.stopCurWithId(firstStartId);
+
+ // Ensure writing no longer allowed.
+ assertWritingContentUriNotAllowed(subUri, "shouldn't write after losing granted URI");
+
+ // And make sure we can't generate a permission to a running service.
+ doTryGrantUriActivityPermissionToSelf(subUri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ doTryGrantUriActivityPermissionToSelf(subUri,
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
+ // --------------------------------
+
+ // Dispose of service.
+ ReceiveUriService.stopSync(getContext());
+
+ // Ensure writing no longer allowed.
+ assertWritingContentUriNotAllowed(subUri, "shouldn't write after losing granted URI");
+ assertWritingContentUriNotAllowed(sub2Uri, "shouldn't write after losing granted URI");
+ }
+
+ public void testGrantReadPermissionFromStartService() {
+ doTestGrantServiceUriReadPermission(PERM_URI_GRANTING);
+ }
+
+ public void testGrantWritePermissionFromStartService() {
+ doTestGrantServiceUriWritePermission(PERM_URI_GRANTING);
+ }
+
+ public void testGrantReadPrivateFromStartService() {
+ doTestGrantServiceUriReadPermission(PRIV_URI_GRANTING);
+ }
+
+ public void testGrantWritePrivateFromStartService() {
+ doTestGrantServiceUriWritePermission(PRIV_URI_GRANTING);
+ }
+
+ /**
+ * Test that ctspermissionwithsignaturepath can't grant read permissions
+ * on paths it doesn't have permission to.
+ */
+ public void testGrantReadUriActivityPathPermissionToSelf() {
+ doTryGrantUriActivityPermissionToSelf(PERM_URI_PATH,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
+
+ /**
+ * Test that ctspermissionwithsignaturepath can't grant write permissions
+ * on paths it doesn't have permission to.
+ */
+ public void testGrantWriteUriActivityPathPermissionToSelf() {
+ doTryGrantUriActivityPermissionToSelf(PERM_URI_PATH,
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ }
+
+ /**
+ * Test that ctspermissionwithsignaturepath can't grant read permissions
+ * on paths it doesn't have permission to.
+ */
+ public void testGrantReadUriActivitySubPathPermissionToSelf() {
+ doTryGrantUriActivityPermissionToSelf(
+ Uri.withAppendedPath(PERM_URI_PATH, "foo"),
+ Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
+
+ /**
+ * Test that ctspermissionwithsignaturepath can't grant write permissions
+ * on paths it doesn't have permission to.
+ */
+ public void testGrantWriteUriActivitySubPathPermissionToSelf() {
+ doTryGrantUriActivityPermissionToSelf(
+ Uri.withAppendedPath(PERM_URI_PATH, "foo"),
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ }
+
+ /**
+ * Test that the ctspermissionwithsignaturepath content provider can grant a read
+ * permission.
+ */
+ public void testGrantReadPathPermissionFromStartActivity() {
+ doTestGrantActivityUriReadPermission(PERM_URI_PATH);
+ }
+
+ /**
+ * Test that the ctspermissionwithsignaturepath content provider can grant a write
+ * permission.
+ */
+ public void testGrantWritePathPermissionFromStartActivity() {
+ doTestGrantActivityUriWritePermission(PERM_URI_PATH);
+ }
+
+ /**
+ * Test that the ctspermissionwithsignaturepath content provider can grant a read
+ * permission.
+ */
+ public void testGrantReadPathPermissionFromStartService() {
+ doTestGrantServiceUriReadPermission(PERM_URI_PATH);
+ }
+
+ /**
+ * Test that the ctspermissionwithsignaturepath content provider can grant a write
+ * permission.
+ */
+ public void testGrantWritePathPermissionFromStartService() {
+ doTestGrantServiceUriWritePermission(PERM_URI_PATH);
+ }
+
+ public void testGetMimeTypePermission() {
+ // Precondition: no current access.
+ assertWritingContentUriNotAllowed(PERM_URI, "shouldn't write when starting test");
+ assertWritingContentUriNotAllowed(PERM_URI, "shouldn't write when starting test");
+
+ // All apps should be able to get MIME type regardless of permission.
+ assertEquals(getContext().getContentResolver().getType(PERM_URI), EXPECTED_MIME_TYPE);
+ }
+
+ public void testGetMimeTypePrivate() {
+ // Precondition: no current access.
+ assertWritingContentUriNotAllowed(PRIV_URI, "shouldn't write when starting test");
+ assertWritingContentUriNotAllowed(PRIV_URI, "shouldn't write when starting test");
+
+ // All apps should be able to get MIME type even if provider is private.
+ assertEquals(getContext().getContentResolver().getType(PRIV_URI), EXPECTED_MIME_TYPE);
+ }
}
diff --git a/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/src/com/android/cts/usespermissiondiffcertapp/ReceiveUriActivity.java b/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/src/com/android/cts/usespermissiondiffcertapp/ReceiveUriActivity.java
new file mode 100644
index 0000000..0ddc4a5
--- /dev/null
+++ b/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/src/com/android/cts/usespermissiondiffcertapp/ReceiveUriActivity.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2010 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.usespermissiondiffcertapp;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.os.MessageQueue.IdleHandler;
+import android.util.Log;
+
+public class ReceiveUriActivity extends Activity {
+ static final String TAG = "ReceiveUriActivity";
+ private static final Object sLock = new Object();
+ private static boolean sStarted;
+ private static boolean sNewIntent;
+ private static boolean sDestroyed;
+ private static ReceiveUriActivity sCurInstance;
+
+ Handler mHandler = new Handler();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ synchronized (sLock) {
+ Log.i(TAG, "onCreate: sCurInstance=" + sCurInstance);
+ if (sCurInstance != null) {
+ finishCurInstance();
+ }
+ sCurInstance = this;
+ sStarted = true;
+ sDestroyed = false;
+ sLock.notifyAll();
+ }
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+
+ synchronized (sLock) {
+ Log.i(TAG, "onNewIntent: sCurInstance=" + sCurInstance);
+ sNewIntent = true;
+ sLock.notifyAll();
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ Log.i(TAG, "onDestroy: sCurInstance=" + sCurInstance);
+ Looper.myQueue().addIdleHandler(new IdleHandler() {
+ @Override
+ public boolean queueIdle() {
+ synchronized (sLock) {
+ sDestroyed = true;
+ sLock.notifyAll();
+ }
+ return false;
+ }
+ });
+ }
+
+ public static void finishCurInstance() {
+ synchronized (sLock) {
+ if (sCurInstance != null) {
+ sCurInstance.finish();
+ sCurInstance = null;
+ }
+ }
+ }
+
+ public static void finishCurInstanceSync() {
+ finishCurInstance();
+
+ synchronized (sLock) {
+ final long startTime = SystemClock.uptimeMillis();
+ while (!sDestroyed) {
+ try {
+ sLock.wait(5000);
+ } catch (InterruptedException e) {
+ }
+ if (SystemClock.uptimeMillis() >= (startTime+5000)) {
+ throw new RuntimeException("Timeout");
+ }
+ }
+ }
+ }
+
+ public static void clearStarted() {
+ synchronized (sLock) {
+ sStarted = false;
+ }
+ }
+
+ public static void clearNewIntent() {
+ synchronized (sLock) {
+ sNewIntent = false;
+ }
+ }
+
+ public static void waitForStart() {
+ synchronized (sLock) {
+ final long startTime = SystemClock.uptimeMillis();
+ while (!sStarted) {
+ try {
+ sLock.wait(5000);
+ } catch (InterruptedException e) {
+ }
+ if (SystemClock.uptimeMillis() >= (startTime+5000)) {
+ throw new RuntimeException("Timeout");
+ }
+ }
+ }
+ }
+
+ public static void waitForNewIntent() {
+ synchronized (sLock) {
+ final long startTime = SystemClock.uptimeMillis();
+ while (!sNewIntent) {
+ try {
+ sLock.wait(5000);
+ } catch (InterruptedException e) {
+ }
+ if (SystemClock.uptimeMillis() >= (startTime+5000)) {
+ throw new RuntimeException("Timeout");
+ }
+ }
+ }
+ }
+}
diff --git a/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/src/com/android/cts/usespermissiondiffcertapp/ReceiveUriService.java b/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/src/com/android/cts/usespermissiondiffcertapp/ReceiveUriService.java
new file mode 100644
index 0000000..68d78c0
--- /dev/null
+++ b/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/src/com/android/cts/usespermissiondiffcertapp/ReceiveUriService.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2010 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.usespermissiondiffcertapp;
+
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.os.MessageQueue.IdleHandler;
+
+public class ReceiveUriService extends Service {
+ private static final Object sLock = new Object();
+ private static boolean sStarted;
+ private static boolean sDestroyed;
+ private static int sCurStartId;
+ private static ReceiveUriService sCurInstance;
+
+ Handler mHandler = new Handler();
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ synchronized (sLock) {
+ sCurStartId = startId;
+ sCurInstance = this;
+ sStarted = true;
+ sDestroyed = false;
+ sLock.notifyAll();
+ }
+
+ return START_REDELIVER_INTENT;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ Looper.myQueue().addIdleHandler(new IdleHandler() {
+ @Override
+ public boolean queueIdle() {
+ synchronized (sLock) {
+ sDestroyed = true;
+ sCurInstance = null;
+ sLock.notifyAll();
+ }
+ return false;
+ }
+ });
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ public static void stop(Context context) {
+ Intent intent = new Intent();
+ intent.setComponent(new ComponentName(
+ "com.android.cts.usespermissiondiffcertapp",
+ "com.android.cts.usespermissiondiffcertapp.ReceiveUriService"));
+ context.stopService(intent);
+ }
+
+ public static int getCurStartId() {
+ synchronized (sLock) {
+ return sCurStartId;
+ }
+ }
+
+ public static void stopCurWithId(int id) {
+ synchronized (sLock) {
+ sCurInstance.stopSelf(id);
+ }
+ }
+
+ public static void stopSync(Context context) {
+ stop(context);
+
+ synchronized (sLock) {
+ final long startTime = SystemClock.uptimeMillis();
+ while (!sDestroyed) {
+ try {
+ sLock.wait(5000);
+ } catch (InterruptedException e) {
+ }
+ if (SystemClock.uptimeMillis() >= (startTime+5000)) {
+ throw new RuntimeException("Timeout");
+ }
+ }
+ }
+ }
+
+ public static void clearStarted() {
+ synchronized (sLock) {
+ sStarted = false;
+ }
+ }
+
+ public static void waitForStart() {
+ synchronized (sLock) {
+ final long startTime = SystemClock.uptimeMillis();
+ while (!sStarted) {
+ try {
+ sLock.wait(5000);
+ } catch (InterruptedException e) {
+ }
+ if (SystemClock.uptimeMillis() >= (startTime+5000)) {
+ throw new RuntimeException("Timeout");
+ }
+ }
+ }
+ }
+}
diff --git a/tests/core/annotation/Android.mk b/tests/core/annotation/Android.mk
deleted file mode 100644
index 4778710..0000000
--- a/tests/core/annotation/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2009 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
-
-#
-# Annotation Tests
-##########################################################
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under,../../../../dalvik/libcore/annotation/src/test/java) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/junit) \
- ../../../../dalvik/libcore/luni/src/test/java/tests/TestSuiteFactory.java
-
-LOCAL_PACKAGE_NAME := android.core.tests.annotation
-
-include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/annotation/AndroidManifest.xml b/tests/core/annotation/AndroidManifest.xml
deleted file mode 100644
index 7e34d2a..0000000
--- a/tests/core/annotation/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2007 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.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/archive/Android.mk b/tests/core/archive/Android.mk
deleted file mode 100644
index 78edd09..0000000
--- a/tests/core/archive/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2009 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
-
-#
-# Archive Tests
-##########################################################
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under,../../../../dalvik/libcore/archive/src/test/java/org) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/junit) \
- $(call all-java-files-under,../../../../dalvik/libcore/support/src/test/java) \
- ../../../../dalvik/libcore/luni/src/test/java/tests/TestSuiteFactory.java
-
-LOCAL_PACKAGE_NAME := android.core.tests.archive
-
-include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/archive/AndroidManifest.xml b/tests/core/archive/AndroidManifest.xml
deleted file mode 100644
index 22ba6f7..0000000
--- a/tests/core/archive/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2007 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.archive">
- <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/concurrent/Android.mk b/tests/core/concurrent/Android.mk
deleted file mode 100644
index d42c6da..0000000
--- a/tests/core/concurrent/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright (C) 2009 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
-
-#
-# Concurrent Tests
-##########################################################
-include $(CLEAR_VARS)
-
-# don't include this package in any target
-LOCAL_MODULE_TAGS := optional
-# and when built explicitly put it in the data partition
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under,../../../../dalvik/libcore/concurrent/src/test/java) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/junit) \
- ../../../../dalvik/libcore/luni/src/test/java/tests/TestSuiteFactory.java
-
-LOCAL_PACKAGE_NAME := android.core.tests.concurrent
-
-include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/concurrent/AndroidManifest.xml b/tests/core/concurrent/AndroidManifest.xml
deleted file mode 100644
index b3ee187..0000000
--- a/tests/core/concurrent/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2007 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.concurrent">
- <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/crypto/Android.mk b/tests/core/crypto/Android.mk
deleted file mode 100644
index 2450ad1..0000000
--- a/tests/core/crypto/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2009 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
-
-#
-# crypto Tests
-##########################################################
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under,../../../../dalvik/libcore/crypto/src/test/java) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/junit) \
- $(call all-java-files-under,../../../../dalvik/libcore/support/src/test/java/) \
- ../../../../dalvik/libcore/luni/src/test/java/tests/TestSuiteFactory.java
-
-LOCAL_PACKAGE_NAME := android.core.tests.crypto
-
-include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/crypto/AndroidManifest.xml b/tests/core/crypto/AndroidManifest.xml
deleted file mode 100644
index 25052ee..0000000
--- a/tests/core/crypto/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2007 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.crypto">
- <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/ctscore.mk b/tests/core/ctscore.mk
index ab7f7be..33fc6f3 100644
--- a/tests/core/ctscore.mk
+++ b/tests/core/ctscore.mk
@@ -17,7 +17,7 @@
# and when built explicitly put them in the data partition
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_JAVA_LIBRARIES := android.test.runner bouncycastle
LOCAL_STATIC_JAVA_LIBRARIES := CtsTestAnnotationsLib
LOCAL_PROGUARD_ENABLED := disabled
diff --git a/tests/core/dom/Android.mk b/tests/core/dom/Android.mk
index 47b3dbb..69d4af3 100644
--- a/tests/core/dom/Android.mk
+++ b/tests/core/dom/Android.mk
@@ -23,10 +23,13 @@
##########################################################
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under,../../../../dalvik/libcore/dom/src/test/java) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/junit) \
- ../../../../dalvik/libcore/luni/src/test/java/tests/TestSuiteFactory.java
+LOCAL_SRC_FILES := $(call all-java-files-under,../../../../libcore/dom/src/test/java) \
+ $(call all-java-files-under,../../../../libcore/junit/src/test/java/junit) \
+ $(call all-java-files-under,../../../../libcore/support/src/test/java/)
LOCAL_PACKAGE_NAME := android.core.tests.dom
+# for java.* javax.* support classes in libcore/support/src/test/java
+LOCAL_DX_FLAGS := --core-library
+
include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/logging/Android.mk b/tests/core/logging/Android.mk
deleted file mode 100644
index 89d1ca9..0000000
--- a/tests/core/logging/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2009 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
-
-#
-# Logging Tests
-##########################################################
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under,../../../../dalvik/libcore/logging/src/test/java) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/junit) \
- $(call all-java-files-under,../../../../dalvik/libcore/support/src/test/java) \
- ../../../../dalvik/libcore/luni/src/test/java/tests/TestSuiteFactory.java
-
-LOCAL_PACKAGE_NAME := android.core.tests.logging
-
-include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/logging/AndroidManifest.xml b/tests/core/logging/AndroidManifest.xml
deleted file mode 100644
index c6e5bee..0000000
--- a/tests/core/logging/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2007 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.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/luni-io/Android.mk b/tests/core/luni-io/Android.mk
index f2aae36..ed39e03 100644
--- a/tests/core/luni-io/Android.mk
+++ b/tests/core/luni-io/Android.mk
@@ -23,14 +23,16 @@
##########################################################
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/tests/api/java/io) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/io) \
- $(call all-java-files-under,../../../../dalvik/libcore/support/src/test/java/) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/org/apache/harmony/luni/tests/pkg1) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/org/apache/harmony/luni/tests/pkg2) \
- ../../../../dalvik/libcore/luni/src/test/java/tests/luni/AllTestsIo.java \
- ../../../../dalvik/libcore/luni/src/test/java/tests/TestSuiteFactory.java
+LOCAL_SRC_FILES := $(call all-java-files-under,../../../../libcore/luni/src/test/java/tests/api/java/io) \
+ $(call all-java-files-under,../../../../libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/io) \
+ $(call all-java-files-under,../../../../libcore/support/src/test/java/) \
+ $(call all-java-files-under,../../../../libcore/luni/src/test/java/org/apache/harmony/luni/tests/pkg1) \
+ $(call all-java-files-under,../../../../libcore/luni/src/test/java/org/apache/harmony/luni/tests/pkg2) \
+ ../../../../libcore/luni/src/test/java/tests/luni/AllTestsIo.java
LOCAL_PACKAGE_NAME := android.core.tests.luni.io
+# for java.* javax.* support classes in libcore/support/src/test/java
+LOCAL_DX_FLAGS := --core-library
+
include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/luni-lang/Android.mk b/tests/core/luni-lang/Android.mk
index 225bdf9..a31b881 100644
--- a/tests/core/luni-lang/Android.mk
+++ b/tests/core/luni-lang/Android.mk
@@ -23,12 +23,14 @@
##########################################################
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/lang) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/tests/api/java/lang) \
- $(call all-java-files-under,../../../../dalvik/libcore/support/src/test/java/) \
- ../../../../dalvik/libcore/luni/src/test/java/tests/luni/AllTestsLang.java \
- ../../../../dalvik/libcore/luni/src/test/java/tests/TestSuiteFactory.java
+LOCAL_SRC_FILES := $(call all-java-files-under,../../../../libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/lang) \
+ $(call all-java-files-under,../../../../libcore/luni/src/test/java/tests/api/java/lang) \
+ $(call all-java-files-under,../../../../libcore/support/src/test/java/) \
+ ../../../../libcore/luni/src/test/java/tests/luni/AllTestsLang.java
LOCAL_PACKAGE_NAME := android.core.tests.luni.lang
+# for java.* javax.* support classes in libcore/support/src/test/java
+LOCAL_DX_FLAGS := --core-library
+
include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/luni-net/Android.mk b/tests/core/luni-net/Android.mk
index 1092ff1..8a6508c 100644
--- a/tests/core/luni-net/Android.mk
+++ b/tests/core/luni-net/Android.mk
@@ -23,14 +23,17 @@
##########################################################
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/tests/api/java/net) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/org/apache/harmony/luni/tests/internal/net/www/protocol/http) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/org/apache/harmony/luni/tests/internal/net/www/protocol/https) \
- $(call all-java-files-under,../../../../dalvik/libcore/support/src/test/java/) \
- ../../../../dalvik/libcore/luni/src/test/java/tests/luni/AllTestsNet.java \
- ../../../../dalvik/libcore/luni/src/test/java/tests/TestSuiteFactory.java
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under,../../../../libcore/luni/src/test/java/libcore/java/net) \
+ $(call all-java-files-under,../../../../libcore/luni/src/test/java/org/apache/harmony/luni/tests/internal/net/www/protocol/http) \
+ $(call all-java-files-under,../../../../libcore/luni/src/test/java/org/apache/harmony/luni/tests/internal/net/www/protocol/https) \
+ $(call all-java-files-under,../../../../libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/net) \
+ $(call all-java-files-under,../../../../libcore/support/src/test/java/) \
+ ../../../../libcore/luni/src/test/java/tests/luni/AllTestsNet.java
LOCAL_PACKAGE_NAME := android.core.tests.luni.net
+# for java.* javax.* support classes in libcore/support/src/test/java
+LOCAL_DX_FLAGS := --core-library
+
include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/luni-util/Android.mk b/tests/core/luni-util/Android.mk
index 101cde8..5468c17 100644
--- a/tests/core/luni-util/Android.mk
+++ b/tests/core/luni-util/Android.mk
@@ -23,12 +23,14 @@
##########################################################
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/util) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/tests/api/java/util) \
- $(call all-java-files-under,../../../../dalvik/libcore/support/src/test/java/) \
- ../../../../dalvik/libcore/luni/src/test/java/tests/luni/AllTestsUtil.java \
- ../../../../dalvik/libcore/luni/src/test/java/tests/TestSuiteFactory.java
+LOCAL_SRC_FILES := $(call all-java-files-under,../../../../libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/util) \
+ $(call all-java-files-under,../../../../libcore/luni/src/test/java/tests/api/java/util) \
+ $(call all-java-files-under,../../../../libcore/support/src/test/java/) \
+ ../../../../libcore/luni/src/test/java/tests/luni/AllTestsUtil.java
LOCAL_PACKAGE_NAME := android.core.tests.luni.util
+# for java.* javax.* support classes in libcore/support/src/test/java
+LOCAL_DX_FLAGS := --core-library
+
include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/math/Android.mk b/tests/core/math/Android.mk
deleted file mode 100644
index 4c559cd..0000000
--- a/tests/core/math/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2009 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
-
-#
-# Math Tests
-##########################################################
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under,../../../../dalvik/libcore/math/src/test/java) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/junit) \
- $(call all-java-files-under,../../../../dalvik/libcore/support/src/test/java) \
- ../../../../dalvik/libcore/luni/src/test/java/tests/TestSuiteFactory.java
-
-LOCAL_PACKAGE_NAME := android.core.tests.math
-
-include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/math/AndroidManifest.xml b/tests/core/math/AndroidManifest.xml
deleted file mode 100644
index f87fa13..0000000
--- a/tests/core/math/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2007 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.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/nio/Android.mk b/tests/core/nio/Android.mk
deleted file mode 100644
index 6ebd1bc..0000000
--- a/tests/core/nio/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2009 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
-
-#
-# Nio Tests
-##########################################################
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under,../../../../dalvik/libcore/nio/src/test/java) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/junit) \
- $(call all-java-files-under,../../../../dalvik/libcore/support/src/test/java) \
- ../../../../dalvik/libcore/luni/src/test/java/tests/TestSuiteFactory.java
-
-LOCAL_PACKAGE_NAME := android.core.tests.nio
-
-include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/nio/AndroidManifest.xml b/tests/core/nio/AndroidManifest.xml
deleted file mode 100644
index 4c79bfa..0000000
--- a/tests/core/nio/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2007 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.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/nio_char/Android.mk b/tests/core/nio_char/Android.mk
deleted file mode 100644
index e3b463a..0000000
--- a/tests/core/nio_char/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2009 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
-
-#
-# NioChar Tests
-##########################################################
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under,../../../../dalvik/libcore/nio_char/src/test/java) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/junit) \
- $(call all-java-files-under,../../../../dalvik/libcore/support/src/test/java) \
- ../../../../dalvik/libcore/luni/src/test/java/tests/TestSuiteFactory.java
-
-LOCAL_PACKAGE_NAME := android.core.tests.nio_char
-
-include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/nio_char/AndroidManifest.xml b/tests/core/nio_char/AndroidManifest.xml
deleted file mode 100644
index b8de2c9..0000000
--- a/tests/core/nio_char/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2007 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.nio_char">
- <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/prefs/Android.mk b/tests/core/prefs/Android.mk
deleted file mode 100644
index f8f225c..0000000
--- a/tests/core/prefs/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2009 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
-
-#
-# Prefs Tests
-##########################################################
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under,../../../../dalvik/libcore/prefs/src/test/java) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/junit) \
- $(call all-java-files-under,../../../../dalvik/libcore/support/src/test/java) \
- ../../../../dalvik/libcore/luni/src/test/java/tests/TestSuiteFactory.java
-
-LOCAL_PACKAGE_NAME := android.core.tests.prefs
-
-include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/prefs/AndroidManifest.xml b/tests/core/prefs/AndroidManifest.xml
deleted file mode 100644
index d994c72..0000000
--- a/tests/core/prefs/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2007 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.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/regex/Android.mk b/tests/core/regex/Android.mk
deleted file mode 100644
index 70927a0..0000000
--- a/tests/core/regex/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2009 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
-
-#
-# Regex Tests
-##########################################################
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under,../../../../dalvik/libcore/regex/src/test/java) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/junit) \
- $(call all-java-files-under,../../../../dalvik/libcore/support/src/test/java) \
- ../../../../dalvik/libcore/luni/src/test/java/tests/TestSuiteFactory.java
-
-LOCAL_PACKAGE_NAME := android.core.tests.regex
-
-include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/regex/AndroidManifest.xml b/tests/core/regex/AndroidManifest.xml
deleted file mode 100644
index ddd2165..0000000
--- a/tests/core/regex/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2007 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.regex">
- <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/security/Android.mk b/tests/core/security/Android.mk
deleted file mode 100644
index 76c0ca5..0000000
--- a/tests/core/security/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2009 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
-
-#
-# Security Tests
-##########################################################
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under,../../../../dalvik/libcore/security/src/test/java) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/junit) \
- $(call all-java-files-under,../../../../dalvik/libcore/support/src/test/java) \
- ../../../../dalvik/libcore/luni/src/test/java/tests/TestSuiteFactory.java
-
-LOCAL_PACKAGE_NAME := android.core.tests.security
-
-include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/security/AndroidManifest.xml b/tests/core/security/AndroidManifest.xml
deleted file mode 100644
index 3960a82..0000000
--- a/tests/core/security/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2007 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.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/sql/Android.mk b/tests/core/sql/Android.mk
deleted file mode 100644
index fe9b4cc..0000000
--- a/tests/core/sql/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2009 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
-
-#
-# Sql Tests
-##########################################################
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under,../../../../dalvik/libcore/sql/src/test/java) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/junit) \
- $(call all-java-files-under,../../../../dalvik/libcore/support/src/test/java) \
- ../../../../dalvik/libcore/luni/src/test/java/tests/TestSuiteFactory.java
-
-LOCAL_PACKAGE_NAME := android.core.tests.sql
-
-include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/sql/AndroidManifest.xml b/tests/core/sql/AndroidManifest.xml
deleted file mode 100644
index 0ebcab6..0000000
--- a/tests/core/sql/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2007 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.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/text/Android.mk b/tests/core/text/Android.mk
deleted file mode 100644
index 8b9fd1f..0000000
--- a/tests/core/text/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2009 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
-
-#
-# Text Tests
-##########################################################
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under,../../../../dalvik/libcore/text/src/test/java) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/junit) \
- $(call all-java-files-under,../../../../dalvik/libcore/support/src/test/java) \
- ../../../../dalvik/libcore/luni/src/test/java/tests/TestSuiteFactory.java
-
-LOCAL_PACKAGE_NAME := android.core.tests.text
-
-include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/text/AndroidManifest.xml b/tests/core/text/AndroidManifest.xml
deleted file mode 100644
index baf0031..0000000
--- a/tests/core/text/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2007 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.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/xml/Android.mk b/tests/core/xml/Android.mk
index ba784b9..4f8af07 100644
--- a/tests/core/xml/Android.mk
+++ b/tests/core/xml/Android.mk
@@ -23,12 +23,20 @@
##########################################################
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under,../../../../dalvik/libcore/xml/src/test/java) \
- $(call all-java-files-under,../../../../dalvik/libcore/dom/src/test) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/junit) \
- $(call all-java-files-under,../../../../dalvik/libcore/support/src/test/java) \
- ../../../../dalvik/libcore/luni/src/test/java/tests/TestSuiteFactory.java
+LOCAL_SRC_FILES := $(call all-java-files-under,../../../../libcore/xml/src/test/java) \
+ $(call all-java-files-under,../../../../libcore/dom/src/test) \
+ $(call all-java-files-under,../../../../libcore/junit/src/test/java/junit) \
+ $(call all-java-files-under,../../../../libcore/luni/src/test/java/org/apache/harmony/xml) \
+ $(call all-java-files-under,../../../../libcore/luni/src/test/java/tests/api/javax/xml/parsers) \
+ $(call all-java-files-under,../../../../libcore/luni/src/test/java/tests/api/org/xml/sax) \
+ $(call all-java-files-under,../../../../libcore/luni/src/test/java/tests/api/org/xml/sax/support) \
+ $(call all-java-files-under,../../../../libcore/luni/src/test/java/tests/org/w3c/dom) \
+ $(call all-java-files-under,../../../../libcore/luni/src/test/java/tests/xml) \
+ $(call all-java-files-under,../../../../libcore/support/src/test/java)
LOCAL_PACKAGE_NAME := android.core.tests.xml
+# for java.* javax.* support classes in libcore/support/src/test/java
+LOCAL_DX_FLAGS := --core-library
+
include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/xnet/Android.mk b/tests/core/xnet/Android.mk
deleted file mode 100644
index 2415f38..0000000
--- a/tests/core/xnet/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2009 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
-
-#
-# Xnet Tests
-##########################################################
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under,../../../../dalvik/libcore/x-net/src/test/java) \
- $(call all-java-files-under,../../../../dalvik/libcore/luni/src/test/java/junit) \
- $(call all-java-files-under,../../../../dalvik/libcore/support/src/test/java) \
- ../../../../dalvik/libcore/luni/src/test/java/tests/TestSuiteFactory.java
-
-LOCAL_PACKAGE_NAME := android.core.tests.xnet
-
-include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/xnet/AndroidManifest.xml b/tests/core/xnet/AndroidManifest.xml
deleted file mode 100644
index 82e5dd7..0000000
--- a/tests/core/xnet/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2007 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.xnet">
- <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/res/values-large/configVarying.xml b/tests/res/values-large/configVarying.xml
new file mode 100755
index 0000000..7b2df7c
--- /dev/null
+++ b/tests/res/values-large/configVarying.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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>
+ <item type="configVarying" name="simple">simple large</item>
+ <bag type="configVarying" name="bag">
+ <item name="testString">bag large</item>
+ </bag>
+ <item type="configVarying" name="large">large</item>
+</resources>
diff --git a/tests/res/values-normal/configVarying.xml b/tests/res/values-normal/configVarying.xml
new file mode 100755
index 0000000..b45ee49
--- /dev/null
+++ b/tests/res/values-normal/configVarying.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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>
+ <item type="configVarying" name="simple">simple normal</item>
+ <bag type="configVarying" name="bag">
+ <item name="testString">bag normal</item>
+ </bag>
+ <item type="configVarying" name="normal">normal</item>
+</resources>
diff --git a/tests/res/values-small/configVarying.xml b/tests/res/values-small/configVarying.xml
new file mode 100755
index 0000000..15a9f8f
--- /dev/null
+++ b/tests/res/values-small/configVarying.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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>
+ <item type="configVarying" name="simple">simple small</item>
+ <bag type="configVarying" name="bag">
+ <item name="testString">bag small</item>
+ </bag>
+ <item type="configVarying" name="small">small</item>
+</resources>
diff --git a/tests/res/values-xlarge/configVarying.xml b/tests/res/values-xlarge/configVarying.xml
new file mode 100755
index 0000000..fb9cad7
--- /dev/null
+++ b/tests/res/values-xlarge/configVarying.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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>
+ <item type="configVarying" name="simple">simple xlarge</item>
+ <bag type="configVarying" name="bag">
+ <item name="testString">bag xlarge</item>
+ </bag>
+ <item type="configVarying" name="xlarge">xlarge</item>
+</resources>
diff --git a/tests/res/values/configVarying.xml b/tests/res/values/configVarying.xml
index a2d5b97..de1b09e 100755
--- a/tests/res/values/configVarying.xml
+++ b/tests/res/values/configVarying.xml
@@ -19,4 +19,8 @@
<bag type="configVarying" name="bag">
<item name="testString">bag default</item>
</bag>
+ <item type="configVarying" name="small">default</item>
+ <item type="configVarying" name="normal">default</item>
+ <item type="configVarying" name="large">default</item>
+ <item type="configVarying" name="xlarge">default</item>
</resources>
diff --git a/tests/src/android/hardware/cts/CameraStubActivity.java b/tests/src/android/hardware/cts/CameraStubActivity.java
index 50bd13b..8ab7fbd 100644
--- a/tests/src/android/hardware/cts/CameraStubActivity.java
+++ b/tests/src/android/hardware/cts/CameraStubActivity.java
@@ -24,9 +24,7 @@
import com.android.cts.stub.R;
public class CameraStubActivity extends Activity {
-
- public static SurfaceView mSurfaceView;
-
+ private SurfaceView mSurfaceView;
private final int LAYOUT_WIDTH = 480;
private final int LAYOUT_HEIGHT = 320;
@@ -43,4 +41,8 @@
mSurfaceView.getHolder().setFixedSize(LAYOUT_WIDTH, LAYOUT_HEIGHT);
mSurfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
+
+ public SurfaceView getSurfaceView() {
+ return mSurfaceView;
+ }
}
diff --git a/tests/src/android/widget/cts/WidgetTestUtils.java b/tests/src/android/widget/cts/WidgetTestUtils.java
index 0a8f6dc..2df6629 100644
--- a/tests/src/android/widget/cts/WidgetTestUtils.java
+++ b/tests/src/android/widget/cts/WidgetTestUtils.java
@@ -48,7 +48,8 @@
}
// b1 and b2 are all not null.
- if (b1.getWidth() != b2.getWidth() || b1.getHeight() != b2.getHeight()) {
+ if (b1.getWidth() != b2.getWidth() || b1.getHeight() != b2.getHeight()
+ || b1.getConfig() != b2.getConfig()) {
Assert.fail("the bitmaps are not equal");
}
@@ -119,4 +120,19 @@
options.inScaled = false;
return BitmapFactory.decodeResource(resources, resId, options);
}
+
+ /**
+ * Retrieve a dithered bitmap that can be used for comparison on any density
+ * @param resources
+ * @param config the preferred config for the returning bitmap
+ * @return the {@link Bitmap} or <code>null</code>
+ */
+ public static Bitmap getUnscaledAndDitheredBitmap(Resources resources,
+ int resId, Bitmap.Config config) {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inDither = true;
+ options.inScaled = false;
+ options.inPreferredConfig = config;
+ return BitmapFactory.decodeResource(resources, resId, options);
+ }
}
diff --git a/tests/tests/app/src/android/app/cts/DialogTest.java b/tests/tests/app/src/android/app/cts/DialogTest.java
index 4d02896..6a48358 100644
--- a/tests/tests/app/src/android/app/cts/DialogTest.java
+++ b/tests/tests/app/src/android/app/cts/DialogTest.java
@@ -518,24 +518,22 @@
assertTrue(d.onKeyDownReturn);
}
- @TestTargetNew(
- level = TestLevel.COMPLETE,
- method = "onKeyMultiple",
- args = {int.class, int.class, android.view.KeyEvent.class}
- )
- public void testOnKeyMultiple() {
- popDialog(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
- final TestDialog d = (TestDialog) mActivity.getDialog();
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "onKeyMultiple",
+ args = {int.class, int.class, android.view.KeyEvent.class}
+ )
+ public void testOnKeyMultiple() {
+ popDialog(DialogStubActivity.TEST_ONSTART_AND_ONSTOP);
+ final TestDialog d = (TestDialog) mActivity.getDialog();
- // System call onTouchEvent
- assertNull(d.keyMultipleEvent);
- mInstrumentation.sendKeySync(
- new KeyEvent(KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_UNKNOWN));
- assertTrue(d.isOnKeyMultipleCalled);
- assertFalse(d.onKeyMultipleReturn);
- assertEquals(KeyEvent.KEYCODE_UNKNOWN, d.keyMultipleEvent.getKeyCode());
- assertEquals(KeyEvent.ACTION_MULTIPLE, d.keyMultipleEvent.getAction());
- }
+ assertNull(d.keyMultipleEvent);
+ d.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_UNKNOWN));
+ assertTrue(d.isOnKeyMultipleCalled);
+ assertFalse(d.onKeyMultipleReturn);
+ assertEquals(KeyEvent.KEYCODE_UNKNOWN, d.keyMultipleEvent.getKeyCode());
+ assertEquals(KeyEvent.ACTION_MULTIPLE, d.keyMultipleEvent.getAction());
+ }
@TestTargets({
@TestTargetNew(
diff --git a/tests/tests/app/src/android/app/cts/InstrumentationTest.java b/tests/tests/app/src/android/app/cts/InstrumentationTest.java
index 5ce33a0..1861ae2 100644
--- a/tests/tests/app/src/android/app/cts/InstrumentationTest.java
+++ b/tests/tests/app/src/android/app/cts/InstrumentationTest.java
@@ -36,10 +36,12 @@
import android.os.IBinder;
import android.os.SystemClock;
import android.test.InstrumentationTestCase;
+import android.view.InputQueue;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
+import android.view.SurfaceHolder;
import android.view.View;
import android.view.Window;
import android.view.ViewGroup.LayoutParams;
@@ -956,6 +958,14 @@
@Override
public void togglePanel(int featureId, KeyEvent event) {
}
+
+ @Override
+ public void takeSurface(SurfaceHolder.Callback2 callback) {
+ }
+
+ @Override
+ public void takeInputQueue(InputQueue.Callback queue) {
+ }
}
}
diff --git a/tests/tests/app/src/android/app/cts/SystemFeaturesTest.java b/tests/tests/app/src/android/app/cts/SystemFeaturesTest.java
index ac3d03a..2ce1e75 100644
--- a/tests/tests/app/src/android/app/cts/SystemFeaturesTest.java
+++ b/tests/tests/app/src/android/app/cts/SystemFeaturesTest.java
@@ -176,8 +176,12 @@
assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_ACCELEROMETER,
Sensor.TYPE_ACCELEROMETER);
+ assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_BAROMETER,
+ Sensor.TYPE_PRESSURE);
assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_COMPASS,
Sensor.TYPE_MAGNETIC_FIELD);
+ assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_GYROSCOPE,
+ Sensor.TYPE_GYROSCOPE);
assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_LIGHT,
Sensor.TYPE_LIGHT);
assertFeatureForSensor(featuresLeft, PackageManager.FEATURE_SENSOR_PROXIMITY,
diff --git a/tests/tests/content/src/android/content/cts/SharedPreferencesTest.java b/tests/tests/content/src/android/content/cts/SharedPreferencesTest.java
new file mode 100644
index 0000000..bc81c4c
--- /dev/null
+++ b/tests/tests/content/src/android/content/cts/SharedPreferencesTest.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2010 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.content.cts;
+
+import com.android.cts.stub.R;
+
+import dalvik.annotation.BrokenTest;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.ToBeFixed;
+
+import android.app.QueuedWork;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
+/**
+ * Test {@link SharedPreferences}.
+ */
+@TestTargetClass(SharedPreferences.class)
+public class SharedPreferencesTest extends AndroidTestCase {
+ private static final String TAG = "SharedPreferencesTest";
+
+ private Context mContext;
+ private ContextWrapper mContextWrapper;
+
+ private File mPrefsFile;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mContext = getContext();
+ mContextWrapper = new ContextWrapper(mContext);
+
+ SharedPreferences prefs = getPrefs();
+ prefs.edit().clear().commit();
+
+ // Duplicated from ContextImpl.java. Not ideal, but there wasn't a better
+ // way to reach into Context{Wrapper,Impl} to ask where this file lives.
+ mPrefsFile = new File("/data/data/com.android.cts.stub/shared_prefs",
+ "com.android.cts.stub_preferences.xml");
+ mPrefsFile.delete();
+ }
+
+ private SharedPreferences getPrefs() {
+ return PreferenceManager.getDefaultSharedPreferences(mContext);
+ }
+
+ public void testNoFileInitially() {
+ assertFalse(mPrefsFile.exists());
+ }
+
+ public void testCommitCreatesFiles() {
+ SharedPreferences prefs = getPrefs();
+ assertFalse(mPrefsFile.exists());
+ prefs.edit().putString("foo", "bar").commit();
+ assertTrue(mPrefsFile.exists());
+ }
+
+ public void testDefaults() {
+ SharedPreferences prefs = getPrefs();
+ String key = "not-set";
+ assertFalse(prefs.contains(key));
+ assertEquals(0, prefs.getAll().size());
+ assertTrue(prefs.getAll().isEmpty());
+ assertEquals(false, prefs.getBoolean(key, false));
+ assertEquals(true, prefs.getBoolean(key, true));
+ assertEquals(0.5f, prefs.getFloat(key, 0.5f));
+ assertEquals(123, prefs.getInt(key, 123));
+ assertEquals(999L, prefs.getLong(key, 999L));
+ assertEquals("default", prefs.getString(key, "default"));
+ }
+
+ private abstract class RedundantWriteTest {
+ // Do some initial operation on editor. No commit needed.
+ public abstract void setUp(SharedPreferences.Editor editor);
+
+ // Do some later operation on editor (e.g. a redundant edit).
+ // No commit needed.
+ public abstract void subsequentEdit(SharedPreferences.Editor editor);
+
+ public boolean expectingMutation() {
+ return false;
+ }
+
+ // Tests that a redundant edit after an initital setup doesn't
+ // result in a duplicate write-out to disk.
+ public final void test() throws Exception {
+ SharedPreferences prefs = getPrefs();
+ SharedPreferences.Editor editor;
+
+ assertFalse(mPrefsFile.exists());
+ prefs.edit().commit();
+ assertTrue(mPrefsFile.exists());
+
+ editor = prefs.edit();
+ setUp(editor);
+ editor.commit();
+ long modtimeMillis1 = mPrefsFile.lastModified();
+
+ // Wait a second and modify the preferences in a dummy,
+ // redundant way. Wish I could inject a clock or disk mock
+ // here, but can't. Instead relying on checking modtime of
+ // file on disk.
+ Thread.sleep(1000); // ms
+
+ editor = prefs.edit();
+ subsequentEdit(editor);
+ editor.commit();
+
+ long modtimeMillis2 = mPrefsFile.lastModified();
+ assertEquals(expectingMutation(), modtimeMillis1 != modtimeMillis2);
+ }
+ };
+
+ public void testRedundantBoolean() throws Exception {
+ new RedundantWriteTest() {
+ public void setUp(SharedPreferences.Editor editor) {
+ editor.putBoolean("foo", true);
+ }
+ public void subsequentEdit(SharedPreferences.Editor editor) {
+ editor.putBoolean("foo", true);
+ }
+ }.test();
+ }
+
+ public void testRedundantString() throws Exception {
+ new RedundantWriteTest() {
+ public void setUp(SharedPreferences.Editor editor) {
+ editor.putString("foo", "bar");
+ }
+ public void subsequentEdit(SharedPreferences.Editor editor) {
+ editor.putString("foo", "bar");
+ }
+ }.test();
+ }
+
+ public void testNonRedundantString() throws Exception {
+ new RedundantWriteTest() {
+ public void setUp(SharedPreferences.Editor editor) {
+ editor.putString("foo", "bar");
+ }
+ public void subsequentEdit(SharedPreferences.Editor editor) {
+ editor.putString("foo", "baz");
+ }
+ public boolean expectingMutation() {
+ return true;
+ }
+ }.test();
+ }
+
+ public void testRedundantClear() throws Exception {
+ new RedundantWriteTest() {
+ public void setUp(SharedPreferences.Editor editor) {
+ editor.clear();
+ }
+ public void subsequentEdit(SharedPreferences.Editor editor) {
+ editor.clear();
+ }
+ }.test();
+ }
+
+ public void testNonRedundantClear() throws Exception {
+ new RedundantWriteTest() {
+ public void setUp(SharedPreferences.Editor editor) {
+ editor.putString("foo", "bar");
+ }
+ public void subsequentEdit(SharedPreferences.Editor editor) {
+ editor.clear();
+ }
+ public boolean expectingMutation() {
+ return true;
+ }
+ }.test();
+ }
+
+ public void testRedundantRemove() throws Exception {
+ new RedundantWriteTest() {
+ public void setUp(SharedPreferences.Editor editor) {
+ editor.putString("foo", "bar");
+ }
+ public void subsequentEdit(SharedPreferences.Editor editor) {
+ editor.remove("not-exist-key");
+ }
+ }.test();
+ }
+
+ public void testRedundantCommitWritesFileIfNotAlreadyExisting() {
+ SharedPreferences prefs = getPrefs();
+ assertFalse(mPrefsFile.exists());
+ prefs.edit().putString("foo", "bar").commit();
+ assertTrue(mPrefsFile.exists());
+
+ // Delete the file out from under it. (not sure why this
+ // would happen in practice, but perhaps the app did it for
+ // some reason...)
+ mPrefsFile.delete();
+
+ // And verify that a redundant edit (which would otherwise not
+ // write do disk), still does write to disk if the file isn't
+ // there.
+ prefs.edit().putString("foo", "bar").commit();
+ assertTrue(mPrefsFile.exists());
+ }
+
+ public void testTorture() {
+ Map<String, String> expectedMap = new HashMap<String, String>();
+ Random rand = new Random();
+
+ SharedPreferences prefs = mContext.getSharedPreferences("torture", Context.MODE_PRIVATE);
+ prefs.edit().clear().commit();
+
+ for (int i = 0; i < 100; i++) {
+ prefs = mContext.getSharedPreferences("torture", Context.MODE_PRIVATE);
+ assertEquals(expectedMap, prefs.getAll());
+
+ String key = new Integer(rand.nextInt(25)).toString();
+ String value = new Integer(i).toString();
+ SharedPreferences.Editor editor = prefs.edit();
+
+ if (rand.nextInt(100) < 85) {
+ Log.d(TAG, "Setting " + key + "=" + value);
+ editor.putString(key, value);
+ expectedMap.put(key, value);
+ } else {
+ Log.d(TAG, "Removing " + key);
+ editor.remove(key);
+ expectedMap.remove(key);
+ }
+
+ // Use apply on most, but commit some too.
+ if (rand.nextInt(100) < 85) {
+ Log.d(TAG, "apply.");
+ editor.apply();
+ } else {
+ Log.d(TAG, "commit.");
+ editor.commit();
+ }
+
+ assertEquals(expectedMap, prefs.getAll());
+ }
+ }
+
+ // Checks that an in-memory commit doesn't mutate a data structure
+ // still being used while writing out to disk.
+ public void testTorture2() {
+ Random rand = new Random();
+
+ for (int fi = 0; fi < 100; fi++) {
+ String prefsName = "torture_" + fi;
+ SharedPreferences prefs = mContext.getSharedPreferences(prefsName, Context.MODE_PRIVATE);
+ prefs.edit().clear().commit();
+ Map<String, String> expectedMap = new HashMap<String, String>();
+
+ for (int applies = 0; applies < 3; applies++) {
+ SharedPreferences.Editor editor = prefs.edit();
+ for (int n = 0; n < 1000; n++) {
+ String key = new Integer(rand.nextInt(25)).toString();
+ String value = new Integer(n).toString();
+ editor.putString(key, value);
+ expectedMap.put(key, value);
+ }
+ editor.apply();
+ }
+ QueuedWork.waitToFinish();
+
+ String clonePrefsName = prefsName + "_clone";
+ File prefsFile = mContext.getSharedPrefsFile(prefsName);
+ File prefsFileClone = mContext.getSharedPrefsFile(clonePrefsName);
+ prefsFileClone.delete();
+ try {
+ FileOutputStream fos = new FileOutputStream(prefsFileClone);
+ FileInputStream fis = new FileInputStream(prefsFile);
+ byte buf[] = new byte[1024];
+ int n;
+ while ((n = fis.read(buf)) > 0) {
+ fos.write(buf, 0, n);
+ }
+ fis.close();
+ fos.close();
+ } catch (IOException e) {
+ }
+
+ SharedPreferences clonePrefs = mContext.getSharedPreferences(
+ clonePrefsName, Context.MODE_PRIVATE);
+ assertEquals(expectedMap, clonePrefs.getAll());
+
+ prefsFile.delete();
+ prefsFileClone.delete();
+ }
+ }
+
+}
diff --git a/tests/tests/content/src/android/content/res/cts/ConfigTest.java b/tests/tests/content/src/android/content/res/cts/ConfigTest.java
index 276cb35..d68fd19 100755
--- a/tests/tests/content/src/android/content/res/cts/ConfigTest.java
+++ b/tests/tests/content/src/android/content/res/cts/ConfigTest.java
@@ -43,7 +43,8 @@
ORIENTATION,
WIDTH,
HEIGHT,
- DENSITY
+ DENSITY,
+ SCREENLAYOUT
}
private static void checkValue(final Resources res, final int resId,
@@ -129,9 +130,11 @@
break;
case DENSITY:
// this is the ratio from the standard
-
mMetrics.density = (((float)value)/((float)DisplayMetrics.DENSITY_DEFAULT));
break;
+ case SCREENLAYOUT:
+ mConfig.screenLayout = value;
+ break;
default:
assert(false);
break;
@@ -303,6 +306,34 @@
checkValue(res, R.configVarying.simple, "simple square");
checkValue(res, R.configVarying.bag,
R.styleable.TestConfig, new String[]{"bag square"});
+
+ config = new TotalConfig();
+ config.setProperty(Properties.SCREENLAYOUT, Configuration.SCREENLAYOUT_SIZE_SMALL);
+ res = config.getResources();
+ checkValue(res, R.configVarying.simple, "simple small");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag small"});
+
+ config = new TotalConfig();
+ config.setProperty(Properties.SCREENLAYOUT, Configuration.SCREENLAYOUT_SIZE_NORMAL);
+ res = config.getResources();
+ checkValue(res, R.configVarying.simple, "simple normal");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag normal"});
+
+ config = new TotalConfig();
+ config.setProperty(Properties.SCREENLAYOUT, Configuration.SCREENLAYOUT_SIZE_LARGE);
+ res = config.getResources();
+ checkValue(res, R.configVarying.simple, "simple large");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag large"});
+
+ config = new TotalConfig();
+ config.setProperty(Properties.SCREENLAYOUT, Configuration.SCREENLAYOUT_SIZE_XLARGE);
+ res = config.getResources();
+ checkValue(res, R.configVarying.simple, "simple xlarge");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag xlarge"});
}
@MediumTest
@@ -378,6 +409,47 @@
R.styleable.TestConfig, new String[]{"bag 240dpi"});
}
+ @MediumTest
+ public void testScreenSize() throws Exception {
+ // ensure that we fall back to the best available screen size
+ // for a given configuration.
+ TotalConfig config = new TotalConfig();
+ config.setProperty(Properties.SCREENLAYOUT, Configuration.SCREENLAYOUT_SIZE_SMALL);
+ Resources res = config.getResources();
+ checkValue(res, R.configVarying.simple, "simple small");
+ checkValue(res, R.configVarying.small, "small");
+ checkValue(res, R.configVarying.normal, "default");
+ checkValue(res, R.configVarying.large, "default");
+ checkValue(res, R.configVarying.xlarge, "default");
+
+ config = new TotalConfig();
+ config.setProperty(Properties.SCREENLAYOUT, Configuration.SCREENLAYOUT_SIZE_NORMAL);
+ res = config.getResources();
+ checkValue(res, R.configVarying.simple, "simple normal");
+ checkValue(res, R.configVarying.small, "default");
+ checkValue(res, R.configVarying.normal, "normal");
+ checkValue(res, R.configVarying.large, "default");
+ checkValue(res, R.configVarying.xlarge, "default");
+
+ config = new TotalConfig();
+ config.setProperty(Properties.SCREENLAYOUT, Configuration.SCREENLAYOUT_SIZE_LARGE);
+ res = config.getResources();
+ checkValue(res, R.configVarying.simple, "simple large");
+ checkValue(res, R.configVarying.small, "default");
+ checkValue(res, R.configVarying.normal, "normal");
+ checkValue(res, R.configVarying.large, "large");
+ checkValue(res, R.configVarying.xlarge, "default");
+
+ config = new TotalConfig();
+ config.setProperty(Properties.SCREENLAYOUT, Configuration.SCREENLAYOUT_SIZE_XLARGE);
+ res = config.getResources();
+ checkValue(res, R.configVarying.simple, "simple xlarge");
+ checkValue(res, R.configVarying.small, "default");
+ checkValue(res, R.configVarying.normal, "normal");
+ checkValue(res, R.configVarying.large, "large");
+ checkValue(res, R.configVarying.xlarge, "xlarge");
+ }
+
// TODO - add tests for special cases - ie, other key params seem ignored if
// nokeys is set
@@ -421,7 +493,8 @@
*/
/**
- * Precidence order: mcc, mnc, locale, orientation, density,
+ * Precidence order: mcc, mnc, locale, screenlayout-size,
+ * screenlayout-long, orientation, density,
* touchscreen, hidden, keyboard, navigation, width-height
*/
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
index f3bfcaf..7287834 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapTest.java
@@ -15,11 +15,12 @@
*/
package android.graphics.cts;
-import java.io.ByteArrayOutputStream;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.IntBuffer;
-import java.nio.ShortBuffer;
+import com.android.cts.stub.R;
+
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -33,16 +34,14 @@
import android.test.AndroidTestCase;
import android.widget.cts.WidgetTestUtils;
-import com.android.cts.stub.R;
-
-import dalvik.annotation.TestLevel;
-import dalvik.annotation.TestTargetClass;
-import dalvik.annotation.TestTargetNew;
-import dalvik.annotation.TestTargets;
+import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
@TestTargetClass(Bitmap.class)
public class BitmapTest extends AndroidTestCase {
- private static final int BUFFER_SIZE = 1016;
private Resources mRes;
private Bitmap mBitmap;
private BitmapFactory.Options mOptions;
@@ -133,49 +132,51 @@
)
})
public void testCopyPixelsToBuffer(){
+ final int pixSize = mBitmap.getRowBytes() * mBitmap.getHeight();
+ final int tooSmall = pixSize / 2;
+
// abnormal case: unsupported Buffer subclass
try{
- mBitmap.copyPixelsToBuffer(CharBuffer.allocate(BUFFER_SIZE));
+ mBitmap.copyPixelsToBuffer(CharBuffer.allocate(pixSize));
fail("shouldn't come to here");
}catch(RuntimeException e1){
}
// abnormal case: Buffer not large enough for pixels
try{
- mBitmap.copyPixelsToBuffer(ByteBuffer.allocate(BUFFER_SIZE));
+ mBitmap.copyPixelsToBuffer(ByteBuffer.allocate(tooSmall));
fail("shouldn't come to here");
}catch(RuntimeException e2){
}
// normal case
- long pixSize = mBitmap.getRowBytes() * mBitmap.getHeight();
- ByteBuffer byteBuf = ByteBuffer.allocate(101608);
+ ByteBuffer byteBuf = ByteBuffer.allocate(pixSize);
assertEquals(0, byteBuf.position());
mBitmap.copyPixelsToBuffer(byteBuf);
assertEquals(pixSize, byteBuf.position());
// abnormal case: Buffer not large enough for pixels
try{
- mBitmap.copyPixelsToBuffer(ByteBuffer.allocate(16));
+ mBitmap.copyPixelsToBuffer(ByteBuffer.allocate(tooSmall));
fail("shouldn't come to here");
}catch(RuntimeException e3){
}
// normal case
- ShortBuffer shortBuf = ShortBuffer.allocate(BUFFER_SIZE);
+ ShortBuffer shortBuf = ShortBuffer.allocate(pixSize);
assertEquals(0, shortBuf.position());
mBitmap.copyPixelsToBuffer(shortBuf);
assertEquals(pixSize >> 1, shortBuf.position());
// abnormal case: Buffer not large enough for pixels
try{
- mBitmap.copyPixelsToBuffer(ByteBuffer.allocate(16));
+ mBitmap.copyPixelsToBuffer(ByteBuffer.allocate(tooSmall));
fail("shouldn't come to here");
}catch(RuntimeException e4){
}
// normal case
- IntBuffer intBuf1 = IntBuffer.allocate(BUFFER_SIZE);
+ IntBuffer intBuf1 = IntBuffer.allocate(pixSize);
assertEquals(0, intBuf1.position());
mBitmap.copyPixelsToBuffer(intBuf1);
assertEquals(pixSize >> 2, intBuf1.position());
@@ -183,7 +184,7 @@
Bitmap bitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(),
mBitmap.getConfig());
bitmap.copyPixelsFromBuffer(intBuf1);
- IntBuffer intBuf2 = IntBuffer.allocate(BUFFER_SIZE);
+ IntBuffer intBuf2 = IntBuffer.allocate(pixSize);
bitmap.copyPixelsToBuffer(intBuf2);
assertEquals(intBuf1.position(), intBuf2.position());
diff --git a/tests/tests/graphics/src/android/graphics/cts/NinePatchTest.java b/tests/tests/graphics/src/android/graphics/cts/NinePatchTest.java
index d69dd4f..041de94 100644
--- a/tests/tests/graphics/src/android/graphics/cts/NinePatchTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/NinePatchTest.java
@@ -34,7 +34,6 @@
import android.graphics.RectF;
import android.graphics.Region;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.Suppress;
@TestTargetClass(NinePatch.class)
public class NinePatchTest extends AndroidTestCase {
@@ -174,7 +173,6 @@
method = "hasAlpha",
args = {}
)
- @Suppress // Suppressed for current release
public void testHasAlpha() {
assertFalse(mNinePatch.hasAlpha());
assertEquals(mNinePatch.hasAlpha(), mBitmap.hasAlpha());
diff --git a/tests/tests/hardware/src/android/hardware/cts/CameraTest.java b/tests/tests/hardware/src/android/hardware/cts/CameraTest.java
index 864a1ab..a261914 100644
--- a/tests/tests/hardware/src/android/hardware/cts/CameraTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/CameraTest.java
@@ -25,10 +25,10 @@
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.hardware.Camera;
+import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.ErrorCallback;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PictureCallback;
-import android.hardware.Camera.PreviewCallback;
import android.hardware.Camera.ShutterCallback;
import android.hardware.Camera.Size;
import android.media.ExifInterface;
@@ -37,6 +37,7 @@
import android.os.Environment;
import android.os.Looper;
import android.test.ActivityInstrumentationTestCase2;
+import android.test.MoreAsserts;
import android.test.UiThreadTest;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
@@ -46,6 +47,8 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
import java.util.List;
/**
@@ -61,7 +64,7 @@
"/test.jpg";
private byte[] mJpegData;
- private boolean mRawPreviewCallbackResult = false;
+ private boolean mPreviewCallbackResult = false;
private boolean mShutterCallbackResult = false;
private boolean mRawPictureCallbackResult = false;
private boolean mJpegPictureCallbackResult = false;
@@ -72,7 +75,7 @@
private static final int WAIT_FOR_FOCUS_TO_COMPLETE = 3000;
private static final int WAIT_FOR_SNAPSHOT_TO_COMPLETE = 5000;
- private RawPreviewCallback mRawPreviewCallback = new RawPreviewCallback();
+ private PreviewCallback mPreviewCallback = new PreviewCallback();
private TestShutterCallback mShutterCallback = new TestShutterCallback();
private RawPictureCallback mRawPictureCallback = new RawPictureCallback();
private JpegPictureCallback mJpegPictureCallback = new JpegPictureCallback();
@@ -111,7 +114,7 @@
* Initializes the message looper so that the Camera object can
* receive the callback messages.
*/
- private void initializeMessageLooper() {
+ private void initializeMessageLooper(final int cameraId) {
final ConditionVariable startDone = new ConditionVariable();
new Thread() {
@Override
@@ -122,7 +125,7 @@
// Save the looper so that we can terminate this thread
// after we are done with it.
mLooper = Looper.myLooper();
- mCamera = Camera.open();
+ mCamera = Camera.open(cameraId);
Log.v(TAG, "camera is opened");
startDone.open();
Looper.loop(); // Blocks forever until Looper.quit() is called.
@@ -153,18 +156,13 @@
}
//Implement the previewCallback
- private final class RawPreviewCallback implements PreviewCallback {
- public void onPreviewFrame(byte [] rawData, Camera camera) {
- if (LOGV) Log.v(TAG, "Preview callback start");
- int rawDataLength = 0;
- if (rawData != null) {
- rawDataLength = rawData.length;
- }
- if (rawDataLength > 0) {
- mRawPreviewCallbackResult = true;
- } else {
- mRawPreviewCallbackResult = false;
- }
+ private final class PreviewCallback
+ implements android.hardware.Camera.PreviewCallback {
+ public void onPreviewFrame(byte [] data, Camera camera) {
+ assertNotNull(data);
+ Size size = camera.getParameters().getPreviewSize();
+ assertEquals(size.width * size.height * 3 / 2, data.length);
+ mPreviewCallbackResult = true;
mCamera.stopPreview();
if (LOGV) Log.v(TAG, "notify the preview callback");
mPreviewDone.open();
@@ -265,10 +263,7 @@
}
private void checkPreviewCallback() throws Exception {
- SurfaceHolder mSurfaceHolder;
-
- mSurfaceHolder = CameraStubActivity.mSurfaceView.getHolder();
- mCamera.setPreviewDisplay(mSurfaceHolder);
+ mCamera.setPreviewDisplay(getActivity().getSurfaceView().getHolder());
if (LOGV) Log.v(TAG, "check preview callback");
mCamera.startPreview();
waitForPreviewDone();
@@ -315,11 +310,17 @@
})
@UiThreadTest
public void testTakePicture() throws Exception {
- initializeMessageLooper();
+ int nCameras = Camera.getNumberOfCameras();
+ for (int id = 0; id < nCameras; id++) {
+ Log.v(TAG, "Camera id=" + id);
+ testTakePictureByCamera(id);
+ }
+ }
+
+ private void testTakePictureByCamera(int cameraId) throws Exception {
+ initializeMessageLooper(cameraId);
Size pictureSize = mCamera.getParameters().getPictureSize();
- SurfaceHolder mSurfaceHolder;
- mSurfaceHolder = CameraStubActivity.mSurfaceView.getHolder();
- mCamera.setPreviewDisplay(mSurfaceHolder);
+ mCamera.setPreviewDisplay(getActivity().getSurfaceView().getHolder());
mCamera.startPreview();
mCamera.autoFocus(mAutoFocusCallback);
assertTrue(waitForFocusDone());
@@ -329,16 +330,12 @@
terminateMessageLooper();
assertTrue(mShutterCallbackResult);
assertTrue(mJpegPictureCallbackResult);
- assertTrue(mJpegData != null);
+ assertNotNull(mJpegData);
Bitmap b = BitmapFactory.decodeByteArray(mJpegData, 0, mJpegData.length);
- assertEquals(b.getWidth(), pictureSize.width);
- assertEquals(b.getHeight(), pictureSize.height);
+ assertEquals(pictureSize.width, b.getWidth());
+ assertEquals(pictureSize.height, b.getHeight());
}
- /*
- * Test case 2: Set the preview and
- * verify the RawPreviewCallback is called
- */
@TestTargets({
@TestTargetNew(
level = TestLevel.COMPLETE,
@@ -377,13 +374,43 @@
)
})
@UiThreadTest
- public void testCheckPreview() throws Exception {
- initializeMessageLooper();
- mCamera.setPreviewCallback(mRawPreviewCallback);
+ public void testPreviewCallback() throws Exception {
+ int nCameras = Camera.getNumberOfCameras();
+ for (int id = 0; id < nCameras; id++) {
+ Log.v(TAG, "Camera id=" + id);
+ testPreviewCallbackByCamera(id);
+ }
+ }
+
+ private void testPreviewCallbackByCamera(int cameraId) throws Exception {
+ initializeMessageLooper(cameraId);
+ mCamera.setPreviewCallback(mPreviewCallback);
mCamera.setErrorCallback(mErrorCallback);
checkPreviewCallback();
terminateMessageLooper();
- assertTrue(mRawPreviewCallbackResult);
+ assertTrue(mPreviewCallbackResult);
+
+ mPreviewCallbackResult = false;
+ initializeMessageLooper(cameraId);
+ checkPreviewCallback();
+ terminateMessageLooper();
+ assertFalse(mPreviewCallbackResult);
+
+ // Test all preview sizes.
+ initializeMessageLooper(cameraId);
+ Parameters parameters = mCamera.getParameters();
+ for (Size size: parameters.getSupportedPreviewSizes()) {
+ mPreviewCallbackResult = false;
+ mCamera.setPreviewCallback(mPreviewCallback);
+ parameters.setPreviewSize(size.width, size.height);
+ mCamera.setParameters(parameters);
+ assertEquals(size, mCamera.getParameters().getPreviewSize());
+ mCamera.startPreview();
+ waitForPreviewDone();
+ assertTrue(mPreviewCallbackResult);
+ mCamera.stopPreview();
+ }
+ terminateMessageLooper();
}
@TestTargetNew(
@@ -393,17 +420,25 @@
)
@UiThreadTest
public void testSetOneShotPreviewCallback() throws Exception {
- initializeMessageLooper();
- mCamera.setOneShotPreviewCallback(mRawPreviewCallback);
- checkPreviewCallback();
- terminateMessageLooper();
- assertTrue(mRawPreviewCallbackResult);
+ int nCameras = Camera.getNumberOfCameras();
+ for (int id = 0; id < nCameras; id++) {
+ Log.v(TAG, "Camera id=" + id);
+ testSetOneShotPreviewCallbackByCamera(id);
+ }
+ }
- mRawPreviewCallbackResult = false;
- initializeMessageLooper();
+ private void testSetOneShotPreviewCallbackByCamera(int cameraId) throws Exception {
+ initializeMessageLooper(cameraId);
+ mCamera.setOneShotPreviewCallback(mPreviewCallback);
checkPreviewCallback();
terminateMessageLooper();
- assertFalse(mRawPreviewCallbackResult);
+ assertTrue(mPreviewCallbackResult);
+
+ mPreviewCallbackResult = false;
+ initializeMessageLooper(cameraId);
+ checkPreviewCallback();
+ terminateMessageLooper();
+ assertFalse(mPreviewCallbackResult);
}
@TestTargetNew(
@@ -413,38 +448,45 @@
)
@UiThreadTest
public void testSetPreviewDisplay() throws Exception {
- SurfaceHolder mSurfaceHolder;
- mSurfaceHolder = CameraStubActivity.mSurfaceView.getHolder();
- initializeMessageLooper();
+ int nCameras = Camera.getNumberOfCameras();
+ for (int id = 0; id < nCameras; id++) {
+ Log.v(TAG, "Camera id=" + id);
+ testSetPreviewDisplayByCamera(id);
+ }
+ }
+
+ private void testSetPreviewDisplayByCamera(int cameraId) throws Exception {
+ SurfaceHolder holder = getActivity().getSurfaceView().getHolder();
+ initializeMessageLooper(cameraId);
// Check the order: startPreview->setPreviewDisplay.
- mCamera.setOneShotPreviewCallback(mRawPreviewCallback);
+ mCamera.setOneShotPreviewCallback(mPreviewCallback);
mCamera.startPreview();
- mCamera.setPreviewDisplay(mSurfaceHolder);
+ mCamera.setPreviewDisplay(holder);
waitForPreviewDone();
terminateMessageLooper();
- assertTrue(mRawPreviewCallbackResult);
+ assertTrue(mPreviewCallbackResult);
// Check the order: setPreviewDisplay->startPreview.
- initializeMessageLooper();
- mRawPreviewCallbackResult = false;
- mCamera.setOneShotPreviewCallback(mRawPreviewCallback);
- mCamera.setPreviewDisplay(mSurfaceHolder);
+ initializeMessageLooper(cameraId);
+ mPreviewCallbackResult = false;
+ mCamera.setOneShotPreviewCallback(mPreviewCallback);
+ mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
waitForPreviewDone();
mCamera.stopPreview();
- assertTrue(mRawPreviewCallbackResult);
+ assertTrue(mPreviewCallbackResult);
// Check the order: setting preview display to null->startPreview->
// setPreviewDisplay.
- mRawPreviewCallbackResult = false;
- mCamera.setOneShotPreviewCallback(mRawPreviewCallback);
+ mPreviewCallbackResult = false;
+ mCamera.setOneShotPreviewCallback(mPreviewCallback);
mCamera.setPreviewDisplay(null);
mCamera.startPreview();
- mCamera.setPreviewDisplay(mSurfaceHolder);
+ mCamera.setPreviewDisplay(holder);
waitForPreviewDone();
terminateMessageLooper();
- assertTrue(mRawPreviewCallbackResult);
+ assertTrue(mPreviewCallbackResult);
}
@TestTargetNew(
@@ -454,7 +496,15 @@
)
@UiThreadTest
public void testDisplayOrientation() throws Exception {
- initializeMessageLooper();
+ int nCameras = Camera.getNumberOfCameras();
+ for (int id = 0; id < nCameras; id++) {
+ Log.v(TAG, "Camera id=" + id);
+ testDisplayOrientationByCamera(id);
+ }
+ }
+
+ private void testDisplayOrientationByCamera(int cameraId) throws Exception {
+ initializeMessageLooper(cameraId);
// Check valid arguments.
mCamera.setDisplayOrientation(0);
@@ -471,9 +521,7 @@
}
// Start preview.
- SurfaceHolder mSurfaceHolder;
- mSurfaceHolder = CameraStubActivity.mSurfaceView.getHolder();
- mCamera.setPreviewDisplay(mSurfaceHolder);
+ mCamera.setPreviewDisplay(getActivity().getSurfaceView().getHolder());
mCamera.startPreview();
// Check setting orientation during preview is not allowed.
@@ -500,8 +548,16 @@
)
})
@UiThreadTest
- public void testAccessParameters() throws Exception {
- initializeMessageLooper();
+ public void testParameters() throws Exception {
+ int nCameras = Camera.getNumberOfCameras();
+ for (int id = 0; id < nCameras; id++) {
+ Log.v(TAG, "Camera id=" + id);
+ testParametersByCamera(id);
+ }
+ }
+
+ private void testParametersByCamera(int cameraId) throws Exception {
+ initializeMessageLooper(cameraId);
// we can get parameters just by getxxx method due to the private constructor
Parameters pSet = mCamera.getParameters();
assertParameters(pSet);
@@ -531,10 +587,10 @@
assertTrue(origPreviewFrameRate > 0);
// The default preview format must be yuv420 (NV21).
- assertTrue(origPreviewFormat == ImageFormat.NV21);
+ assertEquals(ImageFormat.NV21, origPreviewFormat);
// The default picture format must be Jpeg.
- assertTrue(origPictureFormat == ImageFormat.JPEG);
+ assertEquals(ImageFormat.JPEG, origPictureFormat);
// If camera supports flash, the default flash mode must be off.
String flashMode = parameters.getFlashMode();
@@ -551,52 +607,62 @@
float focalLength = parameters.getFocalLength();
float horizontalViewAngle = parameters.getHorizontalViewAngle();
float verticalViewAngle = parameters.getVerticalViewAngle();
+ int jpegQuality = parameters.getJpegQuality();
+ int jpegThumnailQuality = parameters.getJpegThumbnailQuality();
assertTrue(previewSizes != null && previewSizes.size() != 0);
assertTrue(pictureSizes != null && pictureSizes.size() != 0);
assertTrue(previewFormats != null && previewFormats.size() != 0);
assertTrue(pictureFormats != null && pictureFormats.size() != 0);
assertTrue(frameRates != null && frameRates.size() != 0);
assertTrue(focusModes != null && focusModes.size() != 0);
- assertTrue(focusMode != null);
+ assertNotNull(focusMode);
assertTrue(focalLength > 0);
assertTrue(horizontalViewAngle > 0 && horizontalViewAngle <= 360);
assertTrue(verticalViewAngle > 0 && verticalViewAngle <= 360);
Size previewSize = previewSizes.get(0);
Size pictureSize = pictureSizes.get(0);
+ assertTrue(jpegQuality >= 1 && jpegQuality <= 100);
+ assertTrue(jpegThumnailQuality >= 1 && jpegThumnailQuality <= 100);
// If a parameter is supported, both getXXX and getSupportedXXX have to
// be non null.
if (parameters.getWhiteBalance() != null) {
- assertTrue(parameters.getSupportedWhiteBalance() != null);
+ assertNotNull(parameters.getSupportedWhiteBalance());
}
if (parameters.getSupportedWhiteBalance() != null) {
- assertTrue(parameters.getWhiteBalance() != null);
+ assertNotNull(parameters.getWhiteBalance());
}
if (parameters.getColorEffect() != null) {
- assertTrue(parameters.getSupportedColorEffects() != null);
+ assertNotNull(parameters.getSupportedColorEffects());
}
if (parameters.getSupportedColorEffects() != null) {
- assertTrue(parameters.getColorEffect() != null);
+ assertNotNull(parameters.getColorEffect());
}
if (parameters.getAntibanding() != null) {
- assertTrue(parameters.getSupportedAntibanding() != null);
+ assertNotNull(parameters.getSupportedAntibanding());
}
if (parameters.getSupportedAntibanding() != null) {
- assertTrue(parameters.getAntibanding() != null);
+ assertNotNull(parameters.getAntibanding());
}
if (parameters.getSceneMode() != null) {
- assertTrue(parameters.getSupportedSceneModes() != null);
+ assertNotNull(parameters.getSupportedSceneModes());
}
if (parameters.getSupportedSceneModes() != null) {
- assertTrue(parameters.getSceneMode() != null);
+ assertNotNull(parameters.getSceneMode());
}
if (parameters.getFlashMode() != null) {
- assertTrue(parameters.getSupportedFlashModes() != null);
+ assertNotNull(parameters.getSupportedFlashModes());
}
if (parameters.getSupportedFlashModes() != null) {
- assertTrue(parameters.getFlashMode() != null);
+ assertNotNull(parameters.getFlashMode());
}
+ // Check if the sizes value contain invalid characters.
+ assertNoLetters(parameters.get("preview-size-values"), "preview-size-values");
+ assertNoLetters(parameters.get("picture-size-values"), "picture-size-values");
+ assertNoLetters(parameters.get("jpeg-thumbnail-size-values"),
+ "jpeg-thumbnail-size-values");
+
// Set the parameters.
parameters.setPictureFormat(PICTURE_FORMAT);
assertEquals(PICTURE_FORMAT, parameters.getPictureFormat());
@@ -614,20 +680,19 @@
mCamera.setParameters(parameters);
Parameters paramActual = mCamera.getParameters();
- // camera may not accept exact parameters, but values must be in valid range
assertTrue(isValidPixelFormat(paramActual.getPictureFormat()));
- assertEquals(paramActual.getPictureSize().width, pictureSize.width);
- assertEquals(paramActual.getPictureSize().height, pictureSize.height);
+ assertEquals(pictureSize.width, paramActual.getPictureSize().width);
+ assertEquals(pictureSize.height, paramActual.getPictureSize().height);
assertTrue(isValidPixelFormat(paramActual.getPreviewFormat()));
- assertEquals(paramActual.getPreviewSize().width, previewSize.width);
- assertEquals(paramActual.getPreviewSize().height, previewSize.height);
+ assertEquals(previewSize.width, paramActual.getPreviewSize().width);
+ assertEquals(previewSize.height, paramActual.getPreviewSize().height);
assertTrue(paramActual.getPreviewFrameRate() > 0);
checkExposureCompensation(parameters);
}
private void checkExposureCompensation(Parameters parameters) {
- assertEquals(parameters.getExposureCompensation(), 0);
+ assertEquals(0, parameters.getExposureCompensation());
int max = parameters.getMaxExposureCompensation();
int min = parameters.getMinExposureCompensation();
float step = parameters.getExposureCompensationStep();
@@ -664,7 +729,15 @@
})
@UiThreadTest
public void testJpegThumbnailSize() throws Exception {
- initializeMessageLooper();
+ int nCameras = Camera.getNumberOfCameras();
+ for (int id = 0; id < nCameras; id++) {
+ Log.v(TAG, "Camera id=" + id);
+ testJpegThumbnailSizeByCamera(id);
+ }
+ }
+
+ private void testJpegThumbnailSizeByCamera(int cameraId) throws Exception {
+ initializeMessageLooper(cameraId);
// Thumbnail size parameters should have valid values.
Parameters p = mCamera.getParameters();
Size size = p.getJpegThumbnailSize();
@@ -675,57 +748,58 @@
assertTrue(sizes.contains(mCamera.new Size(0, 0)));
// Test if the thumbnail size matches the setting.
- SurfaceHolder mSurfaceHolder;
- mSurfaceHolder = CameraStubActivity.mSurfaceView.getHolder();
- mCamera.setPreviewDisplay(mSurfaceHolder);
+ mCamera.setPreviewDisplay(getActivity().getSurfaceView().getHolder());
mCamera.startPreview();
mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback);
waitForSnapshotDone();
- assertEquals(mJpegPictureCallbackResult, true);
+ assertTrue(mJpegPictureCallbackResult);
ExifInterface exif = new ExifInterface(JPEG_PATH);
assertTrue(exif.hasThumbnail());
byte[] thumb = exif.getThumbnail();
Bitmap b = BitmapFactory.decodeByteArray(thumb, 0, thumb.length);
- assertEquals(b.getWidth(), size.width);
- assertEquals(b.getHeight(), size.height);
+ assertEquals(size.width, b.getWidth());
+ assertEquals(size.height, b.getHeight());
// Test no thumbnail case.
p.setJpegThumbnailSize(0, 0);
mCamera.setParameters(p);
+ Size actual = mCamera.getParameters().getJpegThumbnailSize();
+ assertEquals(0, actual.width);
+ assertEquals(0, actual.height);
mCamera.startPreview();
mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback);
waitForSnapshotDone();
- assertEquals(mJpegPictureCallbackResult, true);
+ assertTrue(mJpegPictureCallbackResult);
exif = new ExifInterface(JPEG_PATH);
- assertTrue(!exif.hasThumbnail());
+ assertFalse(exif.hasThumbnail());
terminateMessageLooper();
}
@UiThreadTest
public void testJpegExif() throws Exception {
- initializeMessageLooper();
+ int nCameras = Camera.getNumberOfCameras();
+ for (int id = 0; id < nCameras; id++) {
+ Log.v(TAG, "Camera id=" + id);
+ testJpegExifByCamera(id);
+ }
+ }
+
+ private void testJpegExifByCamera(int cameraId) throws Exception {
+ initializeMessageLooper(cameraId);
Camera.Parameters parameters = mCamera.getParameters();
- SurfaceHolder mSurfaceHolder;
- mSurfaceHolder = CameraStubActivity.mSurfaceView.getHolder();
- mCamera.setPreviewDisplay(mSurfaceHolder);
+ mCamera.setPreviewDisplay(getActivity().getSurfaceView().getHolder());
mCamera.startPreview();
double focalLength = (double)parameters.getFocalLength();
mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback);
waitForSnapshotDone();
ExifInterface exif = new ExifInterface(JPEG_PATH);
- assertTrue(exif.getAttribute(ExifInterface.TAG_MAKE) != null);
- assertTrue(exif.getAttribute(ExifInterface.TAG_MODEL) != null);
- assertTrue(exif.getAttribute(ExifInterface.TAG_DATETIME) != null);
+ assertNotNull(exif.getAttribute(ExifInterface.TAG_MAKE));
+ assertNotNull(exif.getAttribute(ExifInterface.TAG_MODEL));
+ assertNotNull(exif.getAttribute(ExifInterface.TAG_DATETIME));
assertTrue(exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0) != 0);
assertTrue(exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0) != 0);
- assertEquals(exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE), null);
- assertEquals(exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE), null);
- assertEquals(exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF), null);
- assertEquals(exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF), null);
- assertEquals(exif.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP), null);
- assertEquals(exif.getAttribute(ExifInterface.TAG_GPS_DATESTAMP), null);
- assertEquals(exif.getAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD), null);
+ checkGpsDataNull(exif);
double exifFocalLength = (double)exif.getAttributeDouble(
ExifInterface.TAG_FOCAL_LENGTH, -1);
assertEquals(focalLength, exifFocalLength, 0.001);
@@ -742,17 +816,36 @@
mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback);
waitForSnapshotDone();
exif = new ExifInterface(JPEG_PATH);
- assertTrue(exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE) != null);
- assertTrue(exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE) != null);
- assertTrue(exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF) != null);
- assertTrue(exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF) != null);
- assertTrue(exif.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP) != null);
- assertTrue(exif.getAttribute(ExifInterface.TAG_GPS_DATESTAMP) != null);
+ assertNotNull(exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE));
+ assertNotNull(exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE));
+ assertNotNull(exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF));
+ assertNotNull(exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF));
+ assertNotNull(exif.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP));
+ assertNotNull(exif.getAttribute(ExifInterface.TAG_GPS_DATESTAMP));
assertEquals(thirtyTwoCharacters,
exif.getAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD));
+
+ // Test gps tags do not exist after calling removeGpsData.
+ mCamera.startPreview();
+ parameters.removeGpsData();
+ mCamera.setParameters(parameters);
+ mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback);
+ waitForSnapshotDone();
+ exif = new ExifInterface(JPEG_PATH);
+ checkGpsDataNull(exif);
terminateMessageLooper();
}
+ private void checkGpsDataNull(ExifInterface exif) {
+ assertNull(exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE));
+ assertNull(exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE));
+ assertNull(exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF));
+ assertNull(exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF));
+ assertNull(exif.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP));
+ assertNull(exif.getAttribute(ExifInterface.TAG_GPS_DATESTAMP));
+ assertNull(exif.getAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD));
+ }
+
@TestTargets({
@TestTargetNew(
level = TestLevel.COMPLETE,
@@ -767,10 +860,18 @@
})
@UiThreadTest
public void testLockUnlock() throws Exception {
- initializeMessageLooper();
+ int nCameras = Camera.getNumberOfCameras();
+ for (int id = 0; id < nCameras; id++) {
+ Log.v(TAG, "Camera id=" + id);
+ testLockUnlockByCamera(id);
+ }
+ }
+
+ private void testLockUnlockByCamera(int cameraId) throws Exception {
+ initializeMessageLooper(cameraId);
Camera.Parameters parameters = mCamera.getParameters();
SurfaceHolder surfaceHolder;
- surfaceHolder = CameraStubActivity.mSurfaceView.getHolder();
+ surfaceHolder = getActivity().getSurfaceView().getHolder();
Size size = parameters.getPreviewSize();
mCamera.setParameters(parameters);
mCamera.setPreviewDisplay(surfaceHolder);
@@ -834,41 +935,60 @@
})
@UiThreadTest
public void testPreviewCallbackWithBuffer() throws Exception {
- initializeMessageLooper();
+ int nCameras = Camera.getNumberOfCameras();
+ for (int id = 0; id < nCameras; id++) {
+ Log.v(TAG, "Camera id=" + id);
+ testPreviewCallbackWithBufferByCamera(id);
+ }
+ }
+
+ private void testPreviewCallbackWithBufferByCamera(int cameraId) throws Exception {
+ initializeMessageLooper(cameraId);
SurfaceHolder surfaceHolder;
- surfaceHolder = CameraStubActivity.mSurfaceView.getHolder();
+ surfaceHolder = getActivity().getSurfaceView().getHolder();
mCamera.setPreviewDisplay(surfaceHolder);
- Size size = mCamera.getParameters().getPreviewSize();
+ Parameters parameters = mCamera.getParameters();
PreviewCallbackWithBuffer callback = new PreviewCallbackWithBuffer();
- callback.mBuffer1 = new byte[size.width * size.height * 3 / 2 + 1];
- callback.mBuffer2 = new byte[size.width * size.height * 3 / 2 + 1];
- callback.mBuffer3 = new byte[size.width * size.height * 3 / 2 + 1];
+ // Test all preview sizes.
+ for (Size size: parameters.getSupportedPreviewSizes()) {
+ parameters.setPreviewSize(size.width, size.height);
+ mCamera.setParameters(parameters);
+ assertEquals(size, mCamera.getParameters().getPreviewSize());
+ callback.mNumCbWithBuffer1 = 0;
+ callback.mNumCbWithBuffer2 = 0;
+ callback.mNumCbWithBuffer3 = 0;
+ callback.mBuffer1 = new byte[size.width * size.height * 3 / 2];
+ callback.mBuffer2 = new byte[size.width * size.height * 3 / 2];
+ callback.mBuffer3 = new byte[size.width * size.height * 3 / 2];
- // Test if we can get the preview callbacks with specified buffers.
- mCamera.addCallbackBuffer(callback.mBuffer1);
- mCamera.addCallbackBuffer(callback.mBuffer2);
- mCamera.setPreviewCallbackWithBuffer(callback);
- mCamera.startPreview();
- waitForPreviewDone();
- assertEquals(1, callback.mNumCbWithBuffer1);
- assertEquals(1, callback.mNumCbWithBuffer2);
- assertEquals(0, callback.mNumCbWithBuffer3);
+ // Test if we can get the preview callbacks with specified buffers.
+ mCamera.addCallbackBuffer(callback.mBuffer1);
+ mCamera.addCallbackBuffer(callback.mBuffer2);
+ mCamera.setPreviewCallbackWithBuffer(callback);
+ mCamera.startPreview();
+ waitForPreviewDone();
+ assertEquals(1, callback.mNumCbWithBuffer1);
+ assertEquals(1, callback.mNumCbWithBuffer2);
+ assertEquals(0, callback.mNumCbWithBuffer3);
- // Test if preview callback with buffer still works during preview.
- callback.mNumCbWithBuffer1 = callback.mNumCbWithBuffer2 = 0;
- mCamera.addCallbackBuffer(callback.mBuffer3);
- waitForPreviewDone();
- assertEquals(0, callback.mNumCbWithBuffer1);
- assertEquals(0, callback.mNumCbWithBuffer2);
- assertEquals(1, callback.mNumCbWithBuffer3);
+ // Test if preview callback with buffer still works during preview.
+ mCamera.addCallbackBuffer(callback.mBuffer3);
+ waitForPreviewDone();
+ assertEquals(1, callback.mNumCbWithBuffer1);
+ assertEquals(1, callback.mNumCbWithBuffer2);
+ assertEquals(1, callback.mNumCbWithBuffer3);
+ mCamera.setPreviewCallbackWithBuffer(null);
+ mCamera.stopPreview();
+ }
terminateMessageLooper();
}
- private final class PreviewCallbackWithBuffer implements PreviewCallback {
+ private final class PreviewCallbackWithBuffer
+ implements android.hardware.Camera.PreviewCallback {
public int mNumCbWithBuffer1, mNumCbWithBuffer2, mNumCbWithBuffer3;
public byte[] mBuffer1, mBuffer2, mBuffer3;
public void onPreviewFrame(byte[] data, Camera camera) {
- assert(data != null);
+ assertNotNull(data);
if (data == mBuffer1) {
mNumCbWithBuffer1++;
} else if (data == mBuffer2) {
@@ -905,55 +1025,63 @@
})
@UiThreadTest
public void testZoom() throws Exception {
- initializeMessageLooper();
- testImmediateZoom();
- testSmoothZoom();
- terminateMessageLooper();
+ int nCameras = Camera.getNumberOfCameras();
+ for (int id = 0; id < nCameras; id++) {
+ Log.v(TAG, "Camera id=" + id);
+ initializeMessageLooper(id);
+ testImmediateZoom();
+ testSmoothZoom();
+ terminateMessageLooper();
+ }
}
private void testImmediateZoom() throws Exception {
Parameters parameters = mCamera.getParameters();
if (!parameters.isZoomSupported()) return;
+ mCamera.setPreviewDisplay(getActivity().getSurfaceView().getHolder());
+
// Test the zoom parameters.
- assertEquals(parameters.getZoom(), 0); // default zoom should be 0.
- int maxZoom = parameters.getMaxZoom();
- assertTrue(maxZoom >= 0);
- if (maxZoom > 0) {
+ assertEquals(0, parameters.getZoom()); // default zoom should be 0.
+ for (Size size: parameters.getSupportedPreviewSizes()) {
+ parameters = mCamera.getParameters();
+ parameters.setPreviewSize(size.width, size.height);
+ mCamera.setParameters(parameters);
+ parameters = mCamera.getParameters();
+ int maxZoom = parameters.getMaxZoom();
+ assertTrue(maxZoom >= 0);
+
// Zoom ratios should be sorted from small to large.
List<Integer> ratios = parameters.getZoomRatios();
- assertEquals(ratios.size(), maxZoom + 1);
- assertEquals(ratios.get(0).intValue(), 100);
+ assertEquals(maxZoom + 1, ratios.size());
+ assertEquals(100, ratios.get(0).intValue());
for (int i = 0; i < ratios.size() - 1; i++) {
assertTrue(ratios.get(i) < ratios.get(i + 1));
}
- }
- SurfaceHolder mSurfaceHolder;
- mSurfaceHolder = CameraStubActivity.mSurfaceView.getHolder();
- mCamera.setPreviewDisplay(mSurfaceHolder);
- mCamera.startPreview();
- waitForPreviewDone();
+ mCamera.startPreview();
+ waitForPreviewDone();
- // Test each zoom step.
- for (int i = 0; i <= maxZoom; i++) {
- parameters.setZoom(i);
- mCamera.setParameters(parameters);
- assertEquals(i, parameters.getZoom());
- }
+ // Test each zoom step.
+ for (int i = 0; i <= maxZoom; i++) {
+ parameters.setZoom(i);
+ mCamera.setParameters(parameters);
+ assertEquals(i, mCamera.getParameters().getZoom());
+ }
- // It should throw exception if an invalid value is passed.
- try {
- parameters.setZoom(maxZoom + 1);
- mCamera.setParameters(parameters);
- fail("setZoom should throw exception.");
- } catch (RuntimeException e) {
- // expected
- }
- parameters = mCamera.getParameters();
- assertEquals(maxZoom, parameters.getZoom());
+ // It should throw exception if an invalid value is passed.
+ try {
+ parameters.setZoom(maxZoom + 1);
+ mCamera.setParameters(parameters);
+ fail("setZoom should throw exception.");
+ } catch (RuntimeException e) {
+ // expected
+ }
+ assertEquals(maxZoom, mCamera.getParameters().getZoom());
- mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback);
- waitForSnapshotDone();
+ mCamera.takePicture(mShutterCallback, mRawPictureCallback,
+ mJpegPictureCallback);
+ waitForSnapshotDone();
+ }
}
private void testSmoothZoom() throws Exception {
@@ -961,10 +1089,8 @@
if (!parameters.isSmoothZoomSupported()) return;
assertTrue(parameters.isZoomSupported());
- SurfaceHolder mSurfaceHolder;
- mSurfaceHolder = CameraStubActivity.mSurfaceView.getHolder();
ZoomListener zoomListener = new ZoomListener();
- mCamera.setPreviewDisplay(mSurfaceHolder);
+ mCamera.setPreviewDisplay(getActivity().getSurfaceView().getHolder());
mCamera.setZoomChangeListener(zoomListener);
mCamera.startPreview();
waitForPreviewDone();
@@ -973,8 +1099,10 @@
int maxZoom = parameters.getMaxZoom();
parameters.setZoom(maxZoom);
mCamera.setParameters(parameters);
+ assertEquals(maxZoom, mCamera.getParameters().getZoom());
parameters.setZoom(0);
mCamera.setParameters(parameters);
+ assertEquals(0, mCamera.getParameters().getZoom());
assertFalse(zoomListener.mZoomDone.block(500));
// Nothing will happen if zoom is not moving.
@@ -1000,7 +1128,7 @@
Log.e(TAG, "zoomListener.mStopped = " + zoomListener.mStopped);
zoomListener.mZoomDone.close();
mCamera.startSmoothZoom(maxZoom / 2);
- assertEquals(true, zoomListener.mZoomDone.block(5000));
+ assertTrue(zoomListener.mZoomDone.block(5000));
assertEquals(maxZoom - (maxZoom / 2), zoomListener.mValues.size());
int i = maxZoom - 1;
for(Integer value: zoomListener.mValues) {
@@ -1023,6 +1151,7 @@
zoomListener.mZoomDone.close();
parameters.setZoom(0);
mCamera.setParameters(parameters);
+ assertEquals(0, mCamera.getParameters().getZoom());
mCamera.startSmoothZoom(maxZoom);
mCamera.stopSmoothZoom();
assertTrue(zoomListener.mZoomDone.block(5000));
@@ -1041,11 +1170,484 @@
public void onZoomChange(int value, boolean stopped, Camera camera) {
mValues.add(value);
assertEquals(value, camera.getParameters().getZoom());
- assertEquals(false, mStopped);
+ assertFalse(mStopped);
mStopped = stopped;
if (stopped) {
mZoomDone.open();
}
}
}
+
+ @UiThreadTest
+ public void testFocusDistances() throws Exception {
+ int nCameras = Camera.getNumberOfCameras();
+ for (int id = 0; id < nCameras; id++) {
+ Log.v(TAG, "Camera id=" + id);
+ testFocusDistancesByCamera(id);
+ }
+ }
+
+ private void testFocusDistancesByCamera(int cameraId) throws Exception {
+ initializeMessageLooper(cameraId);
+ mCamera.setPreviewDisplay(getActivity().getSurfaceView().getHolder());
+ mCamera.startPreview();
+ waitForPreviewDone();
+ Parameters parameters = mCamera.getParameters();
+
+ // Test every supported focus mode.
+ for (String focusMode: parameters.getSupportedFocusModes()) {
+ parameters.setFocusMode(focusMode);
+ mCamera.setParameters(parameters);
+ parameters = mCamera.getParameters();
+ assertEquals(focusMode, parameters.getFocusMode());
+ checkFocusDistances(parameters);
+ if (Parameters.FOCUS_MODE_AUTO.equals(focusMode)
+ || Parameters.FOCUS_MODE_MACRO.equals(focusMode)) {
+ mCamera.autoFocus(mAutoFocusCallback);
+ assertTrue(waitForFocusDone());
+ parameters = mCamera.getParameters();
+ checkFocusDistances(parameters);
+ }
+ }
+
+ // Test if the method throws exception if the argument is invalid.
+ try {
+ parameters.getFocusDistances(null);
+ fail("getFocusDistances should not accept null.");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ parameters.getFocusDistances(new float[2]);
+ fail("getFocusDistances should not accept a float array with two elements.");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ parameters.getFocusDistances(new float[4]);
+ fail("getFocusDistances should not accept a float array with four elements.");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ terminateMessageLooper();
+ }
+
+ private void checkFocusDistances(Parameters parameters) {
+ float[] distances = new float[3];
+ parameters.getFocusDistances(distances);
+
+ // Focus distances should be greater than 0.
+ assertTrue(distances[Parameters.FOCUS_DISTANCE_NEAR_INDEX] > 0);
+ assertTrue(distances[Parameters.FOCUS_DISTANCE_OPTIMAL_INDEX] > 0);
+ assertTrue(distances[Parameters.FOCUS_DISTANCE_FAR_INDEX] > 0);
+
+ // Make sure far focus distance >= optimal focus distance >= near focus distance.
+ assertTrue(distances[Parameters.FOCUS_DISTANCE_FAR_INDEX] >=
+ distances[Parameters.FOCUS_DISTANCE_OPTIMAL_INDEX]);
+ assertTrue(distances[Parameters.FOCUS_DISTANCE_OPTIMAL_INDEX] >=
+ distances[Parameters.FOCUS_DISTANCE_NEAR_INDEX]);
+
+ // Far focus distance should be infinity in infinity focus mode.
+ if (Parameters.FOCUS_MODE_INFINITY.equals(parameters.getFocusMode())) {
+ assertEquals(Float.POSITIVE_INFINITY,
+ distances[Parameters.FOCUS_DISTANCE_FAR_INDEX]);
+ }
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "cancelAutofocus",
+ args = {}
+ )
+ })
+ @UiThreadTest
+ public void testCancelAutofocus() throws Exception {
+ int nCameras = Camera.getNumberOfCameras();
+ for (int id = 0; id < nCameras; id++) {
+ Log.v(TAG, "Camera id=" + id);
+ testCancelAutofocusByCamera(id);
+ }
+ }
+
+ private void testCancelAutofocusByCamera(int cameraId) throws Exception {
+ initializeMessageLooper(cameraId);
+ mCamera.setPreviewDisplay(getActivity().getSurfaceView().getHolder());
+ mCamera.startPreview();
+
+ // No op if autofocus is not in progress.
+ mCamera.cancelAutoFocus();
+
+ // Try to cancel autofocus immediately.
+ mCamera.autoFocus(mAutoFocusCallback);
+ mCamera.cancelAutoFocus();
+ checkFocusDistanceNotChanging();
+
+ // Try to cancel autofocus after it starts for some time.
+ mCamera.autoFocus(mAutoFocusCallback);
+ Thread.sleep(500);
+ mCamera.cancelAutoFocus();
+ checkFocusDistanceNotChanging();
+
+ // Try to cancel autofocus after it completes. It should be no op.
+ mCamera.autoFocus(mAutoFocusCallback);
+ assertTrue(waitForFocusDone());
+ mCamera.cancelAutoFocus();
+
+ // Test the case calling cancelAutoFocus and release in a row.
+ mCamera.autoFocus(mAutoFocusCallback);
+ mCamera.cancelAutoFocus();
+ mCamera.release();
+
+ // Ensure the camera can be opened if release is called right after AF.
+ mCamera = Camera.open(cameraId);
+ mCamera.startPreview();
+ mCamera.autoFocus(mAutoFocusCallback);
+ mCamera.release();
+
+ terminateMessageLooper();
+ }
+
+ private void checkFocusDistanceNotChanging() throws Exception {
+ float[] distances1 = new float[3];
+ float[] distances2 = new float[3];
+ Parameters parameters = mCamera.getParameters();
+ parameters.getFocusDistances(distances1);
+ Thread.sleep(100);
+ parameters = mCamera.getParameters();
+ parameters.getFocusDistances(distances2);
+ assertEquals(distances1[Parameters.FOCUS_DISTANCE_NEAR_INDEX],
+ distances2[Parameters.FOCUS_DISTANCE_NEAR_INDEX]);
+ assertEquals(distances1[Parameters.FOCUS_DISTANCE_OPTIMAL_INDEX],
+ distances2[Parameters.FOCUS_DISTANCE_OPTIMAL_INDEX]);
+ assertEquals(distances1[Parameters.FOCUS_DISTANCE_FAR_INDEX],
+ distances2[Parameters.FOCUS_DISTANCE_FAR_INDEX]);
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getNumberOfCameras",
+ args = {int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getCameraInfo",
+ args = {int.class, CameraInfo.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "open",
+ args = {int.class}
+ )
+ })
+ @UiThreadTest
+ public void testMultipleCameras() throws Exception {
+ int nCameras = Camera.getNumberOfCameras();
+ Log.v(TAG, "total " + nCameras + " cameras");
+ assertTrue(nCameras >= 0);
+
+ boolean backCameraExist = false;
+ CameraInfo info = new CameraInfo();
+ for (int i = 0; i < nCameras; i++) {
+ Camera.getCameraInfo(i, info);
+ if (info.facing == CameraInfo.CAMERA_FACING_BACK) {
+ backCameraExist = true;
+ break;
+ }
+ }
+ // Make sure original open still works. It must return a back-facing
+ // camera.
+ mCamera = Camera.open();
+ if (mCamera != null) {
+ mCamera.release();
+ assertTrue(backCameraExist);
+ } else {
+ assertFalse(backCameraExist);
+ }
+
+ for (int id = -1; id <= nCameras; id++) {
+ Log.v(TAG, "testing camera #" + id);
+
+ boolean isBadId = (id < 0 || id >= nCameras);
+
+ try {
+ Camera.getCameraInfo(id, info);
+ if (isBadId) {
+ fail("getCameraInfo should not accept bad cameraId (" + id + ")");
+ }
+ } catch (RuntimeException e) {
+ if (!isBadId) throw e;
+ }
+
+ int facing = info.facing;
+ int orientation = info.orientation;
+ assertTrue(facing == CameraInfo.CAMERA_FACING_BACK ||
+ facing == CameraInfo.CAMERA_FACING_FRONT);
+ assertTrue(orientation == 0 || orientation == 90 ||
+ orientation == 180 || orientation == 270);
+
+ Camera camera = null;
+ try {
+ camera = Camera.open(id);
+ if (isBadId) {
+ fail("open() should not accept bad cameraId (" + id + ")");
+ }
+ } catch (RuntimeException e) {
+ if (!isBadId) throw e;
+ } finally {
+ if (camera != null) {
+ camera.release();
+ }
+ }
+ }
+ }
+
+ @UiThreadTest
+ public void testPreviewPictureSizesCombination() throws Exception {
+ int nCameras = Camera.getNumberOfCameras();
+ for (int id = 0; id < nCameras; id++) {
+ Log.v(TAG, "Camera id=" + id);
+ testPreviewPictureSizesCombinationByCamera(id);
+ }
+ }
+
+ private void testPreviewPictureSizesCombinationByCamera(int cameraId) throws Exception {
+ initializeMessageLooper(cameraId);
+ mCamera.setPreviewDisplay(getActivity().getSurfaceView().getHolder());
+ Parameters parameters = mCamera.getParameters();
+ PreviewCbForPreviewPictureSizesCombination callback =
+ new PreviewCbForPreviewPictureSizesCombination();
+
+ // Test all combination of preview sizes and picture sizes.
+ for (Size previewSize: parameters.getSupportedPreviewSizes()) {
+ for (Size pictureSize: parameters.getSupportedPictureSizes()) {
+ Log.v(TAG, "Test previewSize=(" + previewSize.width + "," +
+ previewSize.height + ") pictureSize=(" +
+ pictureSize.width + "," + pictureSize.height + ")");
+ mPreviewCallbackResult = false;
+ mCamera.setPreviewCallback(callback);
+ callback.expectedPreviewSize = previewSize;
+ parameters.setPreviewSize(previewSize.width, previewSize.height);
+ parameters.setPictureSize(pictureSize.width, pictureSize.height);
+ mCamera.setParameters(parameters);
+ assertEquals(previewSize, mCamera.getParameters().getPreviewSize());
+ assertEquals(pictureSize, mCamera.getParameters().getPictureSize());
+
+ // Check if the preview size is the same as requested.
+ mCamera.startPreview();
+ waitForPreviewDone();
+ assertTrue(mPreviewCallbackResult);
+
+ // Check if the picture size is the same as requested.
+ mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback);
+ waitForSnapshotDone();
+ assertTrue(mJpegPictureCallbackResult);
+ assertNotNull(mJpegData);
+ Bitmap b = BitmapFactory.decodeByteArray(mJpegData, 0, mJpegData.length);
+ assertEquals(pictureSize.width, b.getWidth());
+ assertEquals(pictureSize.height, b.getHeight());
+ b.recycle();
+ b = null;
+ }
+ }
+ terminateMessageLooper();
+ }
+
+ private final class PreviewCbForPreviewPictureSizesCombination
+ implements android.hardware.Camera.PreviewCallback {
+ public Size expectedPreviewSize;
+ public void onPreviewFrame(byte[] data, Camera camera) {
+ assertNotNull(data);
+ Size size = camera.getParameters().getPreviewSize();
+ assertEquals(expectedPreviewSize, size);
+ assertEquals(size.width * size.height * 3 / 2, data.length);
+ camera.setPreviewCallback(null);
+ mPreviewCallbackResult = true;
+ mPreviewDone.open();
+ }
+ }
+
+ public void testPreviewFpsRange() throws Exception {
+ int nCameras = Camera.getNumberOfCameras();
+ for (int id = 0; id < nCameras; id++) {
+ Log.v(TAG, "Camera id=" + id);
+ testPreviewFpsRangeByCamera(id);
+ }
+ }
+
+ private void testPreviewFpsRangeByCamera(int cameraId) throws Exception {
+ initializeMessageLooper(cameraId);
+ mCamera.setPreviewDisplay(getActivity().getSurfaceView().getHolder());
+ mCamera.startPreview();
+
+ // Test if the parameters exists and minimum fps <= maximum fps.
+ int[] defaultFps = new int[2];
+ Parameters parameters = mCamera.getParameters();
+ parameters.getPreviewFpsRange(defaultFps);
+ List<int[]> fpsList = parameters.getSupportedPreviewFpsRange();
+ assertTrue(fpsList.size() > 0);
+ boolean found = false;
+ for(int[] fps: fpsList) {
+ assertTrue(fps[Parameters.PREVIEW_FPS_MIN_INDEX] > 0);
+ assertTrue(fps[Parameters.PREVIEW_FPS_MIN_INDEX] <=
+ fps[Parameters.PREVIEW_FPS_MAX_INDEX]);
+ if (!found && Arrays.equals(defaultFps, fps)) {
+ found = true;
+ }
+ }
+ assertTrue("Preview fps range must be in the supported list.", found);
+
+ // Test if the list is properly sorted.
+ for (int i = 0; i < fpsList.size() - 1; i++) {
+ int minFps1 = fpsList.get(i)[Parameters.PREVIEW_FPS_MIN_INDEX];
+ int maxFps1 = fpsList.get(i)[Parameters.PREVIEW_FPS_MAX_INDEX];
+ int minFps2 = fpsList.get(i + 1)[Parameters.PREVIEW_FPS_MIN_INDEX];
+ int maxFps2 = fpsList.get(i + 1)[Parameters.PREVIEW_FPS_MAX_INDEX];
+ assertTrue(maxFps1 < maxFps2
+ || (maxFps1 == maxFps2 && minFps1 < minFps2));
+ }
+
+ // Test if the actual fps is within fps range.
+ Size size = parameters.getPreviewSize();
+ byte[] buffer1 = new byte[size.width * size.height * 3 / 2];
+ byte[] buffer2 = new byte[size.width * size.height * 3 / 2];
+ byte[] buffer3 = new byte[size.width * size.height * 3 / 2];
+ FpsRangePreviewCb callback = new FpsRangePreviewCb();
+ int[] readBackFps = new int[2];
+ for (int[] fps: fpsList) {
+ parameters = mCamera.getParameters();
+ parameters.setPreviewFpsRange(fps[Parameters.PREVIEW_FPS_MIN_INDEX],
+ fps[Parameters.PREVIEW_FPS_MAX_INDEX]);
+ callback.reset(fps[Parameters.PREVIEW_FPS_MIN_INDEX] / 1000.0,
+ fps[Parameters.PREVIEW_FPS_MAX_INDEX] / 1000.0);
+ mCamera.setParameters(parameters);
+ parameters = mCamera.getParameters();
+ parameters.getPreviewFpsRange(readBackFps);
+ MoreAsserts.assertEquals(fps, readBackFps);
+ mCamera.addCallbackBuffer(buffer1);
+ mCamera.addCallbackBuffer(buffer2);
+ mCamera.addCallbackBuffer(buffer3);
+ mCamera.setPreviewCallbackWithBuffer(callback);
+ mCamera.startPreview();
+ try {
+ // Test the frame rate for a while.
+ Thread.sleep(3000);
+ } catch(Exception e) {
+ // ignore
+ }
+ mCamera.stopPreview();
+ }
+
+ // Test the invalid fps cases.
+ parameters = mCamera.getParameters();
+ parameters.setPreviewFpsRange(-1, -1);
+ try {
+ mCamera.setParameters(parameters);
+ fail("Should throw an exception if fps range is negative.");
+ } catch (RuntimeException e) {
+ // expected
+ }
+ parameters.setPreviewFpsRange(10, 5);
+ try {
+ mCamera.setParameters(parameters);
+ fail("Should throw an exception if fps range is invalid.");
+ } catch (RuntimeException e) {
+ // expected
+ }
+
+ terminateMessageLooper();
+ }
+
+ private final class FpsRangePreviewCb
+ implements android.hardware.Camera.PreviewCallback {
+ private double mMinFps, mMaxFps, mMaxFrameInterval, mMinFrameInterval;
+ // An array storing the arrival time of the frames in the last second.
+ private ArrayList<Long> mFrames = new ArrayList<Long>();
+ private long firstFrameArrivalTime;
+
+ public void reset(double minFps, double maxFps) {
+ this.mMinFps = minFps;
+ this.mMaxFps = maxFps;
+ mMaxFrameInterval = 1000.0 / mMinFps;
+ mMinFrameInterval = 1000.0 / mMaxFps;
+ Log.v(TAG, "Min fps=" + mMinFps + ". Max fps=" + mMaxFps
+ + ". Min frame interval=" + mMinFrameInterval
+ + ". Max frame interval=" + mMaxFrameInterval);
+ mFrames.clear();
+ firstFrameArrivalTime = 0;
+ }
+
+ // This method tests if the actual fps is between minimum and maximum.
+ // It also tests if the frame interval is too long.
+ public void onPreviewFrame(byte[] data, android.hardware.Camera camera) {
+ long arrivalTime = System.currentTimeMillis();
+ camera.addCallbackBuffer(data);
+ if (firstFrameArrivalTime == 0) firstFrameArrivalTime = arrivalTime;
+
+ // Remove the frames that arrived before the last second.
+ Iterator<Long> it = mFrames.iterator();
+ while(it.hasNext()) {
+ long time = it.next();
+ if (arrivalTime - time > 1000 && mFrames.size() > 1) {
+ it.remove();
+ } else {
+ break;
+ }
+ }
+
+ // Start the test after one second.
+ if (arrivalTime - firstFrameArrivalTime > 1000) {
+ assertTrue(mFrames.size() >= 2);
+
+ // Check the frame interval and fps. The interval check
+ // considers the time variance passing frames from the camera
+ // hardware to the callback. It should be a constant time, not a
+ // ratio. The fps check is more strict because individual
+ // variance is averaged out.
+
+ // Check if the frame interval is too large or too small.
+ double intervalMargin = 30; // ms
+ long lastArrivalTime = mFrames.get(mFrames.size() - 1);
+ double interval = arrivalTime - lastArrivalTime;
+ if (LOGV) Log.v(TAG, "Frame interval=" + interval);
+ assertTrue("Frame interval (" + interval + "ms) is too large." +
+ " mMaxFrameInterval=" + mMaxFrameInterval + "ms",
+ interval < mMaxFrameInterval + intervalMargin);
+ assertTrue("Frame interval (" + interval + "ms) is too small." +
+ " mMinFrameInterval=" + mMinFrameInterval + "ms",
+ interval > mMinFrameInterval - intervalMargin);
+
+ // Check if the fps is within range.
+ double fpsMargin = 0.03;
+ double avgInterval = (double)(arrivalTime - mFrames.get(0))
+ / mFrames.size();
+ double fps = 1000.0 / avgInterval;
+ assertTrue("Actual fps (" + fps + ") should be larger than " +
+ "min fps (" + mMinFps + ")",
+ fps >= mMinFps * (1 - fpsMargin));
+ assertTrue("Actual fps (" + fps + ") should be smaller than " +
+ "max fps (" + mMaxFps + ")",
+ fps <= mMaxFps * (1 + fpsMargin));
+ }
+ // Add the arrival time of this frame to the list.
+ mFrames.add(arrivalTime);
+ }
+ }
+
+ private void assertEquals(Size expected, Size actual) {
+ assertEquals(expected.width, actual.width);
+ assertEquals(expected.height, actual.height);
+ }
+
+ private void assertNoLetters(String value, String key) {
+ for (int i = 0; i < value.length(); i++) {
+ char c = value.charAt(i);
+ assertFalse("Parameter contains invalid characters. key,value=("
+ + key + "," + value + ")",
+ Character.isLetter(c) && c != 'x');
+ }
+ }
}
diff --git a/tests/tests/jni/libjnitest/helper.h b/tests/tests/jni/libjnitest/helper.h
index 6771d2f..58a3407 100644
--- a/tests/tests/jni/libjnitest/helper.h
+++ b/tests/tests/jni/libjnitest/helper.h
@@ -47,7 +47,7 @@
* @param ... printf-style arguments
* @return an allocated (char *) containing the formatted result
*/
-char *failure(const char *format, ...);
+char *failure(const char *format, ...) __attribute__((format(printf, 1, 2)));
/**
* Runs a list of tests. It will run all the tests, collecting as output
diff --git a/tests/tests/location/src/android/location/cts/AddressTest.java b/tests/tests/location/src/android/location/cts/AddressTest.java
index 5b17e39..5c77d94 100644
--- a/tests/tests/location/src/android/location/cts/AddressTest.java
+++ b/tests/tests/location/src/android/location/cts/AddressTest.java
@@ -548,7 +548,10 @@
assertEquals(address.getAdminArea(), parcel.readString());
assertEquals(address.getSubAdminArea(), parcel.readString());
assertEquals(address.getLocality(), parcel.readString());
+ assertEquals(address.getSubLocality(), parcel.readString());
assertEquals(address.getThoroughfare(), parcel.readString());
+ assertEquals(address.getSubThoroughfare(), parcel.readString());
+ assertEquals(address.getPremises(), parcel.readString());
assertEquals(address.getPostalCode(), parcel.readString());
assertEquals(address.getCountryCode(), parcel.readString());
assertEquals(address.getCountryName(), parcel.readString());
diff --git a/tests/tests/location/src/android/location/cts/LocationManagerTest.java b/tests/tests/location/src/android/location/cts/LocationManagerTest.java
index a917d1d..48cdade 100755
--- a/tests/tests/location/src/android/location/cts/LocationManagerTest.java
+++ b/tests/tests/location/src/android/location/cts/LocationManagerTest.java
@@ -475,13 +475,6 @@
}
try {
- mManager.requestLocationUpdates(TEST_MOCK_PROVIDER_NAME, 0, 0, listener, null);
- fail("Should throw IllegalArgumentException if param looper is null!");
- } catch (IllegalArgumentException e) {
- // expected
- }
-
- try {
mManager.removeUpdates( (LocationListener) null );
fail("Should throw IllegalArgumentException if listener is null!");
} catch (IllegalArgumentException e) {
diff --git a/tests/tests/media/src/android/media/cts/AudioEffectTest.java b/tests/tests/media/src/android/media/cts/AudioEffectTest.java
new file mode 100644
index 0000000..514f6a7
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/AudioEffectTest.java
@@ -0,0 +1,1379 @@
+/*
+ * Copyright (C) 2010 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.media.cts;
+
+import com.android.cts.stub.R;
+
+import android.content.res.AssetFileDescriptor;
+import android.media.audiofx.AudioEffect;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+import android.media.audiofx.PresetReverb;
+import android.media.audiofx.EnvironmentalReverb;
+import android.media.audiofx.Equalizer;
+import android.media.MediaPlayer;
+
+import android.os.Looper;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+import java.util.UUID;
+
+@TestTargetClass(AudioEffect.class)
+public class AudioEffectTest extends AndroidTestCase {
+
+ private String TAG = "AudioEffectTest";
+ private final static int MIN_NUMBER_EFFECTS = 5;
+ // allow +/- 5% tolerance between set and get delays
+ private final static float DELAY_TOLERANCE = 1.05f;
+ // allow +/- 5% tolerance between set and get ratios
+ private final static float RATIO_TOLERANCE = 1.05f;
+
+ private AudioEffect mEffect = null;
+ private AudioEffect mEffect2 = null;
+ private int mSession = -1;
+ private boolean mHasControl = false;
+ private boolean mIsEnabled = false;
+ private int mChangedParameter = -1;
+ private boolean mInitialized = false;
+ private Looper mLooper = null;
+ private MediaPlayer mMediaPlayer = null;
+ private int mError = 0;
+
+ private final Object mLock = new Object();
+
+
+ //-----------------------------------------------------------------
+ // AUDIOEFFECT TESTS:
+ //----------------------------------
+
+ //-----------------------------------------------------------------
+ // 0 - static methods
+ //----------------------------------
+
+ //Test case 0.0: test queryEffects() and platfrom at least provides Equalizer, Bass Boost,
+ // Virtualizer, Environmental reverb and Preset reverb effects
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "queryEffects",
+ args = {}
+ )
+ })
+ public void test0_0QueryEffects() throws Exception {
+
+ AudioEffect.Descriptor[] desc = AudioEffect.queryEffects();
+
+ assertTrue("test0_0QueryEffects: number of effects < MIN_NUMBER_EFFECTS: "+desc.length,
+ (desc.length >= MIN_NUMBER_EFFECTS));
+
+ boolean hasEQ = false;
+ boolean hasBassBoost = false;
+ boolean hasVirtualizer = false;
+ boolean hasEnvReverb = false;
+ boolean hasPresetReverb = false;
+
+ for (int i = 0; i < desc.length; i++) {
+ if (desc[i].type.equals(AudioEffect.EFFECT_TYPE_EQUALIZER)) {
+ hasEQ = true;
+ } else if (desc[i].type.equals(AudioEffect.EFFECT_TYPE_BASS_BOOST)) {
+ hasBassBoost = true;
+ } else if (desc[i].type.equals(AudioEffect.EFFECT_TYPE_VIRTUALIZER)) {
+ hasVirtualizer = true;
+ } else if (desc[i].type.equals(AudioEffect.EFFECT_TYPE_ENV_REVERB)) {
+ hasEnvReverb = true;
+ } else if (desc[i].type.equals(AudioEffect.EFFECT_TYPE_PRESET_REVERB)) {
+ hasPresetReverb = true;
+ }
+ }
+ assertTrue("test0_0QueryEffects: equalizer not found", hasEQ);
+ assertTrue("test0_0QueryEffects: bass boost not found", hasBassBoost);
+ assertTrue("test0_0QueryEffects: virtualizer not found", hasVirtualizer);
+ assertTrue("test0_0QueryEffects: environmental reverb not found", hasEnvReverb);
+ assertTrue("test0_0QueryEffects: preset reverb not found", hasPresetReverb);
+ }
+
+ //-----------------------------------------------------------------
+ // 1 - constructor
+ //----------------------------------
+
+ //Test case 1.0: test constructor from effect type and get effect ID
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "AudioEffect",
+ args = {UUID.class, UUID.class, int.class, int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getId",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "release",
+ args = {}
+ )
+ })
+ public void test1_0ConstructorFromType() throws Exception {
+ AudioEffect.Descriptor[] desc = AudioEffect.queryEffects();
+ assertTrue("no effects found", (desc.length != 0));
+ for (int i = 0; i < desc.length; i++) {
+ try {
+ AudioEffect effect = new AudioEffect(desc[i].type,
+ AudioEffect.EFFECT_TYPE_NULL,
+ 0,
+ 0);
+ assertNotNull("could not create AudioEffect", effect);
+ try {
+ assertTrue("invalid effect ID", (effect.getId() != 0));
+ } catch (IllegalStateException e) {
+ fail("AudioEffect not initialized");
+ } finally {
+ effect.release();
+ }
+ } catch (IllegalArgumentException e) {
+ fail("Effect not found: "+desc[i].name);
+ } catch (UnsupportedOperationException e) {
+ fail("Effect library not loaded");
+ }
+ }
+ }
+
+ //Test case 1.1: test constructor from effect uuid
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "AudioEffect",
+ args = {UUID.class, UUID.class, int.class, int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getId",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "release",
+ args = {}
+ )
+ })
+ public void test1_1ConstructorFromUuid() throws Exception {
+ AudioEffect.Descriptor[] desc = AudioEffect.queryEffects();
+ assertTrue("no effects found", (desc.length != 0));
+ for (int i = 0; i < desc.length; i++) {
+ try {
+ AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_NULL,
+ desc[i].uuid,
+ 0,
+ 0);
+ assertNotNull("could not create AudioEffect", effect);
+ try {
+ assertTrue("invalid effect ID", (effect.getId() != 0));
+ } catch (IllegalStateException e) {
+ fail("AudioEffect not initialized");
+ } finally {
+ effect.release();
+ }
+ } catch (IllegalArgumentException e) {
+ fail("Effect not found: "+desc[i].name);
+ } catch (UnsupportedOperationException e) {
+ fail("Effect library not loaded");
+ }
+ }
+ }
+
+ //Test case 1.2: test constructor failure from unknown type
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "AudioEffect",
+ args = {UUID.class, UUID.class, int.class, int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "release",
+ args = {}
+ )
+ })
+ public void test1_2ConstructorUnknownType() throws Exception {
+
+ try {
+ AudioEffect effect = new AudioEffect(UUID.randomUUID(),
+ AudioEffect.EFFECT_TYPE_NULL,
+ 0,
+ 0);
+ fail("could create random AudioEffect");
+ if (effect != null) {
+ effect.release();
+ }
+ } catch (IllegalArgumentException e) {
+
+ } catch (UnsupportedOperationException e) {
+ fail("Effect library not loaded");
+ }
+ }
+
+ //Test case 1.3: test getEnabled() failure when called on released effect
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "AudioEffect",
+ args = {UUID.class, UUID.class, int.class, int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getEnabled",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "release",
+ args = {}
+ )
+ })
+ public void test1_3GetEnabledAfterRelease() throws Exception {
+
+ try {
+ AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+ AudioEffect.EFFECT_TYPE_NULL,
+ 0,
+ 0);
+ assertNotNull("could not create AudioEffect", effect);
+ effect.release();
+ try {
+ effect.getEnabled();
+ fail("getEnabled() processed after release()");
+ } catch (IllegalStateException e) {
+
+ }
+ } catch (IllegalArgumentException e) {
+ fail("AudioEffect not found");
+ } catch (UnsupportedOperationException e) {
+ fail("Effect library not loaded");
+ }
+ }
+
+ //Test case 1.4: test contructor on mediaPlayer audio session
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnabled",
+ args = {boolean.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "MediaPlayer.getAudioSessionId",
+ args = {}
+ )
+ })
+ public void test1_4InsertOnMediaPlayer() throws Exception {
+ MediaPlayer mp = new MediaPlayer();
+ assertNotNull("could not create mediaplayer", mp);
+ AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(R.raw.testmp3);
+ mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
+ afd.close();
+ getEffect(AudioEffect.EFFECT_TYPE_EQUALIZER, mp.getAudioSessionId());
+ try {
+ mEffect.setEnabled(true);
+
+ } catch (IllegalStateException e) {
+ fail("AudioEffect not initialized");
+ } finally {
+ mp.release();
+ releaseEffect();
+ }
+ }
+
+ //Test case 1.5: test auxiliary effect attachement on MediaPlayer
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getId",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "MediaPlayer.attachAuxEffect",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "MediaPlayer.setAuxEffectSendLevel",
+ args = {}
+ )
+ })
+ public void test1_5AuxiliaryOnMediaPlayer() throws Exception {
+ createMediaPlayerLooper();
+ synchronized(mLock) {
+ try {
+ mLock.wait(1000);
+ } catch(Exception e) {
+ fail("Looper creation: wait was interrupted.");
+ }
+ }
+ assertTrue(mInitialized); // mMediaPlayer has been initialized?
+ mError = 0;
+
+ AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(R.raw.testmp3);
+ mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
+ afd.close();
+ getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
+ try {
+ synchronized(mLock) {
+ try {
+ mMediaPlayer.attachAuxEffect(mEffect.getId());
+ mMediaPlayer.setAuxEffectSendLevel(1.0f);
+ mLock.wait(200);
+ } catch(Exception e) {
+ fail("Attach effect: wait was interrupted.");
+ }
+ }
+ assertTrue("error on attachAuxEffect", mError == 0);
+
+ } catch (IllegalStateException e) {
+ fail("attach aux effect failed");
+ } finally {
+ terminateMediaPlayerLooper();
+ releaseEffect();
+ }
+ }
+
+ //Test case 1.6: test auxiliary effect attachement failure before setDatasource
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getId",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "MediaPlayer.attachAuxEffect",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "MediaPlayer.setAuxEffectSendLevel",
+ args = {}
+ )
+ })
+ public void test1_6AuxiliaryOnMediaPlayerFailure() throws Exception {
+ createMediaPlayerLooper();
+ synchronized(mLock) {
+ try {
+ mLock.wait(1000);
+ } catch(Exception e) {
+ fail("Looper creation: wait was interrupted.");
+ }
+ }
+ assertTrue(mInitialized); // mMediaPlayer has been initialized?
+ mError = 0;
+
+ getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
+ try {
+ synchronized(mLock) {
+ try {
+ mMediaPlayer.attachAuxEffect(mEffect.getId());
+ mLock.wait(1000);
+ } catch(Exception e) {
+ fail("Attach effect: wait was interrupted.");
+ }
+ }
+ assertTrue("no error on attachAuxEffect", mError != 0);
+
+ } catch (IllegalStateException e) {
+ fail("attach aux effect failed");
+ } finally {
+ terminateMediaPlayerLooper();
+ releaseEffect();
+ }
+ }
+
+
+ //Test case 1.7: test auxiliary effect attachement on AudioTrack
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getId",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "AudioTrack.attachAuxEffect",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "AudioTrack.setAuxEffectSendLevel",
+ args = {}
+ )
+ })
+ public void test1_7AuxiliaryOnAudioTrack() throws Exception {
+ AudioTrack track = null;
+ getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
+ try {
+ track = new AudioTrack(
+ AudioManager.STREAM_MUSIC,
+ 44100,
+ AudioFormat.CHANNEL_OUT_MONO,
+ AudioFormat.ENCODING_PCM_16BIT,
+ AudioTrack.getMinBufferSize(44100,
+ AudioFormat.CHANNEL_OUT_MONO,
+ AudioFormat.ENCODING_PCM_16BIT),
+ AudioTrack.MODE_STREAM);
+ assertNotNull("could not create AudioTrack", track);
+
+ int status = track.attachAuxEffect(mEffect.getId());
+ if (status != AudioTrack.SUCCESS) {
+ fail("could not attach aux effect");
+ }
+ status = track.setAuxEffectSendLevel(1.0f);
+ if (status != AudioTrack.SUCCESS) {
+ fail("could not set send level");
+ }
+ } catch (IllegalStateException e) {
+ fail("could not attach aux effect");
+ } catch (IllegalArgumentException e) {
+ fail("could not create AudioTrack");
+ } finally {
+ if (track != null) {
+ track.release();
+ }
+ releaseEffect();
+ }
+ }
+
+ //-----------------------------------------------------------------
+ // 2 - enable/ disable
+ //----------------------------------
+
+
+ //Test case 2.0: test setEnabled() and getEnabled() in valid state
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnabled",
+ args = {boolean.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getEnabled",
+ args = {}
+ )
+ })
+ public void test2_0SetEnabledGetEnabled() throws Exception {
+
+ try {
+ AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+ AudioEffect.EFFECT_TYPE_NULL,
+ 0,
+ 0);
+ assertNotNull("could not create AudioEffect", effect);
+ try {
+ effect.setEnabled(true);
+ assertTrue("invalid state from getEnabled", effect.getEnabled());
+ effect.setEnabled(false);
+ assertFalse("invalid state to getEnabled", effect.getEnabled());
+
+ } catch (IllegalStateException e) {
+ fail("setEnabled() in wrong state");
+ } finally {
+ effect.release();
+ }
+ } catch (IllegalArgumentException e) {
+ fail("AudioEffect not found");
+
+ } catch (UnsupportedOperationException e) {
+ fail("Effect library not loaded");
+ }
+ }
+
+ //Test case 2.1: test setEnabled() throws exception after release
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnabled",
+ args = {boolean.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getEnabled",
+ args = {}
+ )
+ })
+ public void test2_1SetEnabledAfterRelease() throws Exception {
+
+ try {
+ AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+ AudioEffect.EFFECT_TYPE_NULL,
+ 0,
+ 0);
+ assertNotNull("could not create AudioEffect", effect);
+ effect.release();
+ try {
+ effect.setEnabled(true);
+ fail("setEnabled() processed after release");
+ } catch (IllegalStateException e) {
+ // test passed
+ }
+ } catch (IllegalArgumentException e) {
+ fail("AudioEffect not found");
+ } catch (UnsupportedOperationException e) {
+ fail("Effect library not loaded");
+ }
+ }
+
+ //-----------------------------------------------------------------
+ // 3 - set/get parameters
+ //----------------------------------
+
+ //Test case 3.0: test setParameter(byte[], byte[]) / getParameter(byte[], byte[])
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setParameter",
+ args = {byte[].class, byte[].class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getParameter",
+ args = {byte[].class, byte[].class}
+ )
+ })
+ public void test3_0SetParameterByteArrayByteArray() throws Exception {
+ getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
+ try {
+ byte[] param = mEffect.intToByteArray(PresetReverb.PARAM_PRESET);
+ byte[] value = new byte[2];
+ int status = mEffect.getParameter(param, value);
+ assertEquals("getParameter 1 failed", AudioEffect.SUCCESS, status);
+ short preset = PresetReverb.PRESET_SMALLROOM;
+ if (mEffect.byteArrayToShort(value) == preset) {
+ preset = PresetReverb.PRESET_MEDIUMROOM;
+ }
+ value = mEffect.shortToByteArray(preset);
+ status = mEffect.setParameter(param, value);
+ assertEquals("setParameter failed", AudioEffect.SUCCESS, status);
+ status = mEffect.getParameter(param, value);
+ assertEquals("getParameter 2 failed", AudioEffect.SUCCESS, status);
+ assertEquals("get/set Parameter failed", preset,
+ mEffect.byteArrayToShort(value));
+
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("setParameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("setParameter() called in wrong state");
+ } finally {
+ releaseEffect();
+ }
+ }
+
+ //Test case 3.1: test setParameter(int, int) / getParameter(int, int[])
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setParameter",
+ args = {int.class, int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getParameter",
+ args = {int.class, int[].class}
+ )
+ })
+ public void test3_1SetParameterIntInt() throws Exception {
+ getEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB, 0);
+ try {
+ int param = EnvironmentalReverb.PARAM_DECAY_TIME;
+ int[] value = new int[1];
+ int status = mEffect.getParameter(param, value);
+ assertEquals("getParameter 1 failed", AudioEffect.SUCCESS, status);
+ int time = 500;
+ if (value[0] == time) {
+ time = 1000;
+ }
+ status = mEffect.setParameter(param, time);
+ assertEquals("setParameter failed", AudioEffect.SUCCESS, status);
+ status = mEffect.getParameter(param, value);
+ assertEquals("getParameter 2 failed", AudioEffect.SUCCESS, status);
+ assertTrue("got incorrect decay time",
+ ((float)value[0] > (float)(time / DELAY_TOLERANCE)) &&
+ ((float)value[0] < (float)(time * DELAY_TOLERANCE)));
+
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("setParameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("setParameter() called in wrong state");
+ } finally {
+ releaseEffect();
+ }
+ }
+
+ //Test case 3.2: test setParameter(int, short) / getParameter(int, short[])
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setParameter",
+ args = {int.class, short.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getParameter",
+ args = {int.class, short[].class}
+ )
+ })
+ public void test3_2SetParameterIntShort() throws Exception {
+ getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
+ try {
+ int param = PresetReverb.PARAM_PRESET;
+ short[] value = new short[1];
+ int status = mEffect.getParameter(param, value);
+ assertEquals("getParameter 1 failed", AudioEffect.SUCCESS, status);
+ short preset = PresetReverb.PRESET_SMALLROOM;
+ if (value[0] == preset) {
+ preset = PresetReverb.PRESET_MEDIUMROOM;
+ }
+ status = mEffect.setParameter(param, preset);
+ assertEquals("setParameter failed", AudioEffect.SUCCESS, status);
+ status = mEffect.getParameter(param, value);
+ assertEquals("getParameter 2 failed", AudioEffect.SUCCESS, status);
+ assertEquals("get/set Parameter failed", preset, value[0]);
+
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("setParameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("setParameter() called in wrong state");
+ } finally {
+ releaseEffect();
+ }
+ }
+
+ //Test case 3.3: test setParameter(int, byte[]) / getParameter(int, byte[])
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setParameter",
+ args = {int.class, byte[].class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getParameter",
+ args = {int.class, byte[].class}
+ )
+ })
+ public void test3_3SetParameterIntByteArray() throws Exception {
+ getEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB, 0);
+ try {
+ int param = EnvironmentalReverb.PARAM_DECAY_TIME;
+ byte[] value = new byte[4];
+ int status = mEffect.getParameter(param, value);
+ assertEquals("getParameter 1 failed", AudioEffect.SUCCESS, status);
+ int time = 500;
+ if (mEffect.byteArrayToInt(value) == time) {
+ time = 1000;
+ }
+ value = mEffect.intToByteArray(time);
+ status = mEffect.setParameter(param, value);
+ assertEquals("setParameter failed", AudioEffect.SUCCESS, status);
+ status = mEffect.getParameter(param, value);
+ assertEquals("getParameter 2 failed", AudioEffect.SUCCESS, status);
+ int time2 = mEffect.byteArrayToInt(value);
+ assertTrue("got incorrect decay time",
+ ((float)time2 > (float)(time / DELAY_TOLERANCE)) &&
+ ((float)time2 < (float)(time * DELAY_TOLERANCE)));
+
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("setParameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("setParameter() called in wrong state");
+ } finally {
+ releaseEffect();
+ }
+ }
+
+ //Test case 3.4: test setParameter(int[], int[]) / getParameter(int[], int[])
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setParameter",
+ args = {int[].class, int[].class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getParameter",
+ args = {int[].class, int[].class}
+ )
+ })
+ public void test3_4SetParameterIntArrayIntArray() throws Exception {
+ getEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB, 0);
+ try {
+ int[] param = new int[1];
+ int[] value = new int[1];
+ param[0] = EnvironmentalReverb.PARAM_DECAY_TIME;
+ int status = mEffect.getParameter(param, value);
+ assertEquals("getParameter 1 failed", AudioEffect.SUCCESS, status);
+ int[] time = new int[1];
+ time[0] = 500;
+ if (value[0] == time[0]) {
+ time[0] = 1000;
+ }
+ status = mEffect.setParameter(param, time);
+ assertEquals("setParameter failed", AudioEffect.SUCCESS, status);
+ status = mEffect.getParameter(param, value);
+ assertEquals("getParameter 2 failed", AudioEffect.SUCCESS, status);
+ assertTrue("got incorrect decay time",
+ ((float)value[0] > (float)(time[0] / DELAY_TOLERANCE)) &&
+ ((float)value[0] < (float)(time[0] * DELAY_TOLERANCE)));
+
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("setParameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("setParameter() called in wrong state");
+ } finally {
+ releaseEffect();
+ }
+ }
+
+ //Test case 3.5: test setParameter(int[], short[]) / getParameter(int[], short[])
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setParameter",
+ args = {int[].class, short[].class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getParameter",
+ args = {int[].class, short[].class}
+ )
+ })
+
+ public void test3_5SetParameterIntArrayShortArray() throws Exception {
+ getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
+ try {
+ int[] param = new int[1];
+ param[0] = PresetReverb.PARAM_PRESET;
+ short[] value = new short[1];
+ int status = mEffect.getParameter(param, value);
+ assertEquals("getParameter 1 failed", AudioEffect.SUCCESS, status);
+ short[] preset = new short[1];
+ preset[0] = PresetReverb.PRESET_SMALLROOM;
+ if (value[0] == preset[0]) {
+ preset[0] = PresetReverb.PRESET_MEDIUMROOM;
+ }
+ status = mEffect.setParameter(param, preset);
+ assertEquals("setParameter failed", AudioEffect.SUCCESS, status);
+ status = mEffect.getParameter(param, value);
+ assertEquals("getParameter 2 failed", AudioEffect.SUCCESS, status);
+ assertEquals("get/set Parameter failed", preset[0], value[0]);
+
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("setParameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("setParameter() called in wrong state");
+ } finally {
+ releaseEffect();
+ }
+ }
+
+ //Test case 3.6: test setParameter(int[], byte[]) / getParameter(int[], byte[])
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setParameter",
+ args = {int[].class, byte[].class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getParameter",
+ args = {int[].class, byte[].class}
+ )
+ })
+ public void test3_6SetParameterIntArrayByteArray() throws Exception {
+ getEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB, 0);
+ try {
+ int[] param = new int[1];
+ param[0] = EnvironmentalReverb.PARAM_DECAY_TIME;
+ byte[] value = new byte[4];
+ int status = mEffect.getParameter(param, value);
+ assertEquals("getParameter 1 failed", AudioEffect.SUCCESS, status);
+ int time = 500;
+ if (mEffect.byteArrayToInt(value) == time) {
+ time = 1000;
+ }
+
+ status = mEffect.setParameter(param, mEffect.intToByteArray(time));
+ assertEquals("setParameter failed", AudioEffect.SUCCESS, status);
+ status = mEffect.getParameter(param, value);
+ assertEquals("getParameter 2 failed", AudioEffect.SUCCESS, status);
+ int time2 = mEffect.byteArrayToInt(value);
+ assertTrue("got incorrect decay time",
+ ((float)time2 > (float)(time / DELAY_TOLERANCE)) &&
+ ((float)time2 < (float)(time * DELAY_TOLERANCE)));
+
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("setParameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("setParameter() called in wrong state");
+ } finally {
+ releaseEffect();
+ }
+ }
+
+ //Test case 3.7: test setParameter() throws exception after release()
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setParameter",
+ args = {int.class, short.class}
+ )
+ })
+ public void test3_7SetParameterAfterRelease() throws Exception {
+ AudioEffect effect = null;
+ try {
+ effect = new AudioEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB,
+ AudioEffect.EFFECT_TYPE_NULL,
+ 0,
+ 0);
+ assertNotNull("could not create AudioEffect", effect);
+ effect.release();
+ effect.setParameter(PresetReverb.PARAM_PRESET, PresetReverb.PRESET_SMALLROOM);
+ fail("setParameter() processed after release");
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("setParameter() rejected");
+ } catch (IllegalStateException e) {
+ // test passed
+ } finally {
+ if (effect != null) {
+ effect.release();
+ }
+ }
+ }
+
+ //Test case 3.8: test getParameter() throws exception after release()
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setParameter",
+ args = {int.class, short[].class}
+ )
+ })
+ public void test3_8GetParameterAfterRelease() throws Exception {
+ AudioEffect effect = null;
+ try {
+ effect = new AudioEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB,
+ AudioEffect.EFFECT_TYPE_NULL,
+ 0,
+ 0);
+ assertNotNull("could not create AudioEffect", effect);
+ effect.release();
+ short[] value = new short[1];
+ effect.getParameter(PresetReverb.PARAM_PRESET, value);
+ fail("getParameter() processed after release");
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("getParameter() rejected");
+ } catch (IllegalStateException e) {
+ // test passed
+ } finally {
+ if (effect != null) {
+ effect.release();
+ }
+ }
+ }
+
+ //-----------------------------------------------------------------
+ // 4 priority and listeners
+ //----------------------------------
+
+ //Test case 4.0: test control passed to higher priority client
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "hasControl",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnabled",
+ args = {boolean.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getEnabled",
+ args = {}
+ )
+ })
+ public void test4_0setEnabledLowerPriority() throws Exception {
+ AudioEffect effect1 = null;
+ AudioEffect effect2 = null;
+ try {
+ effect1 = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+ AudioEffect.EFFECT_TYPE_NULL,
+ 0,
+ 0);
+ effect2 = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
+ AudioEffect.EFFECT_TYPE_NULL,
+ 1,
+ 0);
+
+ assertNotNull("could not create AudioEffect", effect1);
+ assertNotNull("could not create AudioEffect", effect2);
+
+ assertTrue("Effect2 does not have control", effect2.hasControl());
+ assertFalse("Effect1 has control", effect1.hasControl());
+ assertTrue("Effect1 can enable",
+ effect1.setEnabled(true) == AudioEffect.ERROR_INVALID_OPERATION);
+ assertFalse("Effect1 has enabled", effect2.getEnabled());
+
+ } catch (IllegalArgumentException e) {
+ fail("Effect not found");
+ } catch (UnsupportedOperationException e) {
+ fail("Effect library not loaded");
+ } finally {
+ if (effect1 != null) {
+ effect1.release();
+ }
+ if (effect2 != null) {
+ effect2.release();
+ }
+ }
+ }
+
+ //Test case 4.1: test control passed to higher priority client
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setParameter",
+ args = {int.class, short.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getParameter",
+ args = {int.class, short[].class}
+ )
+ })
+ public void test4_1setParameterLowerPriority() throws Exception {
+ AudioEffect effect1 = null;
+ AudioEffect effect2 = null;
+ try {
+ effect1 = new AudioEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB,
+ AudioEffect.EFFECT_TYPE_NULL,
+ 0,
+ 0);
+ effect2 = new AudioEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB,
+ AudioEffect.EFFECT_TYPE_NULL,
+ 1,
+ 0);
+
+ assertNotNull("could not create AudioEffect", effect1);
+ assertNotNull("could not create AudioEffect", effect2);
+
+ int status = effect2.setParameter(PresetReverb.PARAM_PRESET,
+ PresetReverb.PRESET_SMALLROOM);
+ assertEquals("Effect2 setParameter failed",
+ AudioEffect.SUCCESS, status);
+
+ status = effect1.setParameter(PresetReverb.PARAM_PRESET,
+ PresetReverb.PRESET_MEDIUMROOM);
+ assertEquals("Effect1 setParameter did not fail",
+ AudioEffect.ERROR_INVALID_OPERATION, status);
+
+ short[] value = new short[1];
+ status = effect2.getParameter(PresetReverb.PARAM_PRESET, value);
+ assertEquals("Effect2 getParameter failed",
+ AudioEffect.SUCCESS, status);
+ assertEquals("Effect1 changed parameter", PresetReverb.PRESET_SMALLROOM
+ , value[0]);
+
+
+ } catch (IllegalArgumentException e) {
+ fail("Effect not found");
+ } catch (UnsupportedOperationException e) {
+ fail("Effect library not loaded");
+ } finally {
+ if (effect1 != null) {
+ effect1.release();
+ }
+ if (effect2 != null) {
+ effect2.release();
+ }
+ }
+ }
+
+ //Test case 4.2: test control status listener
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setControlStatusListener",
+ args = {AudioEffect.OnControlStatusChangeListener.class}
+ )
+ })
+ public void test4_2ControlStatusListener() throws Exception {
+
+ mHasControl = true;
+ createListenerLooper(true, false, false);
+ synchronized(mLock) {
+ try {
+ mLock.wait(1000);
+ } catch(Exception e) {
+ fail("Looper creation: wait was interrupted.");
+ }
+ }
+ assertTrue(mInitialized);
+ synchronized(mLock) {
+ try {
+ getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
+ mLock.wait(1000);
+ } catch(Exception e) {
+ fail("Create second effect: wait was interrupted.");
+ } finally {
+ releaseEffect();
+ terminateListenerLooper();
+ }
+ }
+ assertFalse("effect control not lost by effect1", mHasControl);
+ }
+
+ //Test case 4.3: test enable status listener
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnableStatusListener",
+ args = {AudioEffect.OnEnableStatusChangeListener.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnabled",
+ args = {boolean.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getEnabled",
+ args = {}
+ )
+ })
+ public void test4_3EnableStatusListener() throws Exception {
+
+ createListenerLooper(false, true, false);
+ synchronized(mLock) {
+ try {
+ mLock.wait(1000);
+ } catch(Exception e) {
+ fail("Looper creation: wait was interrupted.");
+ }
+ }
+ assertTrue(mInitialized);
+ mEffect2.setEnabled(true);
+ mIsEnabled = true;
+
+ getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
+ assertTrue("effect not enabled", mEffect.getEnabled());
+ synchronized(mLock) {
+ try {
+ mEffect.setEnabled(false);
+ mLock.wait(1000);
+ } catch(Exception e) {
+ fail("Second effect setEnabled: wait was interrupted.");
+ } finally {
+ releaseEffect();
+ terminateListenerLooper();
+ }
+ }
+ assertFalse("enable status not updated", mIsEnabled);
+ }
+
+ //Test case 4.4: test parameter changed listener
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setParameterListener",
+ args = {AudioEffect.OnParameterChangeListener.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setParameter",
+ args = {int.class, short.class}
+ )
+ })
+ public void test4_4ParameterChangedListener() throws Exception {
+
+ createListenerLooper(false, false, true);
+ synchronized(mLock) {
+ try {
+ mLock.wait(1000);
+ } catch(Exception e) {
+ fail("Looper creation: wait was interrupted.");
+ }
+ }
+ assertTrue(mInitialized);
+ int status = mEffect2.setParameter(PresetReverb.PARAM_PRESET,
+ PresetReverb.PRESET_SMALLROOM);
+ assertEquals("mEffect2 setParameter failed",
+ AudioEffect.SUCCESS, status);
+ getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
+ synchronized(mLock) {
+ try {
+ mChangedParameter = -1;
+ mEffect.setParameter(PresetReverb.PARAM_PRESET,
+ PresetReverb.PRESET_MEDIUMROOM);
+ mLock.wait(1000);
+ } catch(Exception e) {
+ fail("set Parameter: wait was interrupted.");
+ } finally {
+ releaseEffect();
+ terminateListenerLooper();
+ }
+ }
+ assertEquals("parameter change not received",
+ PresetReverb.PARAM_PRESET, mChangedParameter);
+ }
+
+ //-----------------------------------------------------------------
+ // 5 command method
+ //----------------------------------
+
+
+ //Test case 5.0: test command method
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "command",
+ args = {int.class, byte[].class, byte[].class}
+ )
+ })
+ public void test5_0Command() throws Exception {
+ getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
+ try {
+ byte[] cmd = new byte[0];
+ byte[] reply = new byte[4];
+ // command 3 is ENABLE
+ int status = mEffect.command(3, cmd, reply);
+ assertEquals("command failed", AudioEffect.SUCCESS, status);
+ assertTrue("effect not enabled", mEffect.getEnabled());
+
+ } catch (IllegalStateException e) {
+ fail("command in illegal state");
+ } finally {
+ releaseEffect();
+ }
+ }
+
+
+ //-----------------------------------------------------------------
+ // private methods
+ //----------------------------------
+
+ private void getEffect(UUID type, int session) {
+ if (mEffect == null || session != mSession) {
+ if (session != mSession && mEffect != null) {
+ mEffect.release();
+ mEffect = null;
+ }
+ try {
+ mEffect = new AudioEffect(type,
+ AudioEffect.EFFECT_TYPE_NULL,
+ 0,
+ session);
+ mSession = session;
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "getEffect() AudioEffect not found exception: "+e);
+ } catch (UnsupportedOperationException e) {
+ Log.e(TAG, "getEffect() Effect library not loaded exception: "+e);
+ }
+ }
+ assertNotNull("could not create mEffect", mEffect);
+ }
+
+ private void releaseEffect() {
+ if (mEffect != null) {
+ mEffect.release();
+ mEffect = null;
+ }
+ }
+
+ // Initializes the equalizer listener looper
+ class ListenerThread extends Thread {
+ boolean mControl;
+ boolean mEnable;
+ boolean mParameter;
+
+ public ListenerThread(boolean control, boolean enable, boolean parameter) {
+ super();
+ mControl = control;
+ mEnable = enable;
+ mParameter = parameter;
+ }
+ }
+
+ private void createListenerLooper(boolean control, boolean enable, boolean parameter) {
+ mInitialized = false;
+ new ListenerThread(control, enable, parameter) {
+ @Override
+ public void run() {
+ // Set up a looper
+ Looper.prepare();
+
+ // Save the looper so that we can terminate this thread
+ // after we are done with it.
+ mLooper = Looper.myLooper();
+
+ mEffect2 = new AudioEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB,
+ AudioEffect.EFFECT_TYPE_NULL,
+ 0,
+ 0);
+ assertNotNull("could not create Equalizer2", mEffect2);
+
+ if (mControl) {
+ mEffect2.setControlStatusListener(
+ new AudioEffect.OnControlStatusChangeListener() {
+ public void onControlStatusChange(
+ AudioEffect effect, boolean controlGranted) {
+ synchronized(mLock) {
+ if (effect == mEffect2) {
+ mHasControl = controlGranted;
+ mLock.notify();
+ }
+ }
+ }
+ });
+ }
+ if (mEnable) {
+ mEffect2.setEnableStatusListener(
+ new AudioEffect.OnEnableStatusChangeListener() {
+ public void onEnableStatusChange(AudioEffect effect, boolean enabled) {
+ synchronized(mLock) {
+ if (effect == mEffect2) {
+ mIsEnabled = enabled;
+ mLock.notify();
+ }
+ }
+ }
+ });
+ }
+ if (mParameter) {
+ mEffect2.setParameterListener(new AudioEffect.OnParameterChangeListener() {
+ public void onParameterChange(AudioEffect effect, int status, byte[] param,
+ byte[] value)
+ {
+ synchronized(mLock) {
+ if (effect == mEffect2) {
+ mChangedParameter = mEffect2.byteArrayToInt(param);
+ mLock.notify();
+ }
+ }
+ }
+ });
+ }
+
+ synchronized(mLock) {
+ mInitialized = true;
+ mLock.notify();
+ }
+ Looper.loop(); // Blocks forever until Looper.quit() is called.
+ }
+ }.start();
+ }
+
+ // Terminates the listener looper thread.
+ private void terminateListenerLooper() {
+ if (mEffect2 != null) {
+ mEffect2.release();
+ mEffect2 = null;
+ }
+ if (mLooper != null) {
+ mLooper.quit();
+ mLooper = null;
+ }
+ }
+
+ /*
+ * Initializes the message looper so that the MediaPlayer object can
+ * receive the callback messages.
+ */
+ private void createMediaPlayerLooper() {
+ mInitialized = false;
+ new Thread() {
+ @Override
+ public void run() {
+ // Set up a looper to be used by mMediaPlayer.
+ Looper.prepare();
+
+ // Save the looper so that we can terminate this thread
+ // after we are done with it.
+ mLooper = Looper.myLooper();
+
+ mMediaPlayer = new MediaPlayer();
+ mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
+ public boolean onError(MediaPlayer player, int what, int extra) {
+ synchronized(mLock) {
+ mError = what;
+ mLock.notify();
+ }
+ return true;
+ }
+ });
+ mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
+ public void onCompletion(MediaPlayer player) {
+ synchronized(mLock) {
+ mLock.notify();
+ }
+ }
+ });
+ synchronized(mLock) {
+ mInitialized = true;
+ mLock.notify();
+ }
+ Looper.loop(); // Blocks forever until Looper.quit() is called.
+ }
+ }.start();
+ }
+ /*
+ * Terminates the message looper thread.
+ */
+ private void terminateMediaPlayerLooper() {
+ if (mLooper != null) {
+ mLooper.quit();
+ mLooper = null;
+ }
+ if (mMediaPlayer != null) {
+ mMediaPlayer.release();
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/tests/tests/media/src/android/media/cts/BassBoostTest.java b/tests/tests/media/src/android/media/cts/BassBoostTest.java
new file mode 100644
index 0000000..9cea0b0
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/BassBoostTest.java
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2010 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.media.cts;
+
+import android.media.audiofx.AudioEffect;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.audiofx.BassBoost;
+import android.os.Looper;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+
+@TestTargetClass(BassBoost.class)
+public class BassBoostTest extends AndroidTestCase {
+
+ private String TAG = "BassBoostTest";
+ private final static short TEST_STRENGTH = 500;
+ private final static short TEST_STRENGTH2 = 1000;
+ private final static float STRENGTH_TOLERANCE = 1.1f; // 10%
+
+ private BassBoost mBassBoost = null;
+ private BassBoost mBassBoost2 = null;
+ private int mSession = -1;
+ private boolean mHasControl = false;
+ private boolean mIsEnabled = false;
+ private int mChangedParameter = -1;
+ private boolean mInitialized = false;
+ private Looper mLooper = null;
+ private final Object mLock = new Object();
+
+ //-----------------------------------------------------------------
+ // BASS BOOST TESTS:
+ //----------------------------------
+
+ //-----------------------------------------------------------------
+ // 0 - constructor
+ //----------------------------------
+
+ //Test case 0.0: test constructor and release
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "BassBoost",
+ args = {int.class, int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getId",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "release",
+ args = {}
+ )
+ })
+ public void test0_0ConstructorAndRelease() throws Exception {
+ BassBoost eq = null;
+ try {
+ eq = new BassBoost(0, 0);
+ assertNotNull("could not create BassBoost", eq);
+ try {
+ assertTrue("invalid effect ID", (eq.getId() != 0));
+ } catch (IllegalStateException e) {
+ fail("BassBoost not initialized");
+ }
+ // test passed
+ } catch (IllegalArgumentException e) {
+ fail("BassBoost not found");
+ } catch (UnsupportedOperationException e) {
+ fail("Effect library not loaded");
+ } finally {
+ if (eq != null) {
+ eq.release();
+ }
+ }
+ }
+
+
+ //-----------------------------------------------------------------
+ // 1 - get/set parameters
+ //----------------------------------
+
+ //Test case 1.0: test strength
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getStrengthSupported",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setStrength",
+ args = {short.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getRoundedStrength",
+ args = {}
+ )
+ })
+ public void test1_0Strength() throws Exception {
+ getBassBoost(0);
+ try {
+ if (mBassBoost.getStrengthSupported()) {
+ short strength = mBassBoost.getRoundedStrength();
+ strength = (strength == TEST_STRENGTH) ? TEST_STRENGTH2 : TEST_STRENGTH;
+ mBassBoost.setStrength((short)strength);
+ short strength2 = mBassBoost.getRoundedStrength();
+ // allow STRENGTH_TOLERANCE difference between set strength and rounded strength
+ assertTrue("got incorrect strength",
+ ((float)strength2 > (float)strength / STRENGTH_TOLERANCE) &&
+ ((float)strength2 < (float)strength * STRENGTH_TOLERANCE));
+ } else {
+ short strength = mBassBoost.getRoundedStrength();
+ assertTrue("got incorrect strength", strength >= 0 && strength <= 1000);
+ }
+ // test passed
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("get parameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("get parameter() called in wrong state");
+ } finally {
+ releaseBassBoost();
+ }
+ }
+
+ //Test case 1.1: test properties
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getProperties",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setProperties",
+ args = {BassBoost.Settings.class}
+ )
+ })
+ public void test1_1Properties() throws Exception {
+ getBassBoost(0);
+ try {
+ BassBoost.Settings settings = mBassBoost.getProperties();
+ String str = settings.toString();
+ settings = new BassBoost.Settings(str);
+
+ short strength = settings.strength;
+ if (mBassBoost.getStrengthSupported()) {
+ strength = (strength == TEST_STRENGTH) ? TEST_STRENGTH2 : TEST_STRENGTH;
+ }
+ settings.strength = strength;
+ mBassBoost.setProperties(settings);
+ settings = mBassBoost.getProperties();
+
+ if (mBassBoost.getStrengthSupported()) {
+ // allow STRENGTH_TOLERANCE difference between set strength and rounded strength
+ assertTrue("got incorrect strength",
+ ((float)settings.strength > (float)strength / STRENGTH_TOLERANCE) &&
+ ((float)settings.strength < (float)strength * STRENGTH_TOLERANCE));
+ }
+ // test passed
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("get parameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("get parameter() called in wrong state");
+ } finally {
+ releaseBassBoost();
+ }
+ }
+
+ //Test case 1.2: test setStrength() throws exception after release
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "release",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setStrength",
+ args = {short.class}
+ )
+ })
+ public void test1_2SetStrengthAfterRelease() throws Exception {
+ getBassBoost(0);
+ mBassBoost.release();
+ try {
+ mBassBoost.setStrength(TEST_STRENGTH);
+ fail("setStrength() processed after release()");
+ } catch (IllegalStateException e) {
+ // test passed
+ } finally {
+ releaseBassBoost();
+ }
+ }
+
+ //-----------------------------------------------------------------
+ // 2 - Effect enable/disable
+ //----------------------------------
+
+ //Test case 2.0: test setEnabled() and getEnabled() in valid state
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnabled",
+ args = {boolean.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getEnabled",
+ args = {}
+ )
+ })
+ public void test2_0SetEnabledGetEnabled() throws Exception {
+ getBassBoost(0);
+ try {
+ mBassBoost.setEnabled(true);
+ assertTrue("invalid state from getEnabled", mBassBoost.getEnabled());
+ mBassBoost.setEnabled(false);
+ assertFalse("invalid state to getEnabled", mBassBoost.getEnabled());
+ // test passed
+ } catch (IllegalStateException e) {
+ fail("setEnabled() in wrong state");
+ } finally {
+ releaseBassBoost();
+ }
+ }
+
+ //Test case 2.1: test setEnabled() throws exception after release
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "release",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnabled",
+ args = {boolean.class}
+ )
+ })
+ public void test2_1SetEnabledAfterRelease() throws Exception {
+ getBassBoost(0);
+ mBassBoost.release();
+ try {
+ mBassBoost.setEnabled(true);
+ fail("setEnabled() processed after release()");
+ } catch (IllegalStateException e) {
+ // test passed
+ } finally {
+ releaseBassBoost();
+ }
+ }
+
+ //-----------------------------------------------------------------
+ // 3 priority and listeners
+ //----------------------------------
+
+ //Test case 3.0: test control status listener
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setControlStatusListener",
+ args = {AudioEffect.OnControlStatusChangeListener.class}
+ )
+ })
+ public void test3_0ControlStatusListener() throws Exception {
+ mHasControl = true;
+ createListenerLooper(true, false, false);
+ synchronized(mLock) {
+ try {
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Looper creation: wait was interrupted.");
+ }
+ }
+ assertTrue(mInitialized);
+ synchronized(mLock) {
+ try {
+ getBassBoost(0);
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Create second effect: wait was interrupted.");
+ } finally {
+ releaseBassBoost();
+ terminateListenerLooper();
+ }
+ }
+ assertFalse("effect control not lost by effect1", mHasControl);
+ }
+
+ //Test case 3.1: test enable status listener
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnableStatusListener",
+ args = {AudioEffect.OnEnableStatusChangeListener.class}
+ )
+ })
+ public void test3_1EnableStatusListener() throws Exception {
+ createListenerLooper(false, true, false);
+ synchronized(mLock) {
+ try {
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Looper creation: wait was interrupted.");
+ }
+ }
+ assertTrue(mInitialized);
+ mBassBoost2.setEnabled(true);
+ mIsEnabled = true;
+ getBassBoost(0);
+ synchronized(mLock) {
+ try {
+ mBassBoost.setEnabled(false);
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Create second effect: wait was interrupted.");
+ } finally {
+ releaseBassBoost();
+ terminateListenerLooper();
+ }
+ }
+ assertFalse("enable status not updated", mIsEnabled);
+ }
+
+ //Test case 3.2: test parameter changed listener
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setParameterListener",
+ args = {BassBoost.OnParameterChangeListener.class}
+ )
+ })
+ public void test3_2ParameterChangedListener() throws Exception {
+ createListenerLooper(false, false, true);
+ synchronized(mLock) {
+ try {
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Looper creation: wait was interrupted.");
+ }
+ }
+ assertTrue(mInitialized);
+ getBassBoost(0);
+ synchronized(mLock) {
+ try {
+ mChangedParameter = -1;
+ mBassBoost.setStrength(TEST_STRENGTH);
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Create second effect: wait was interrupted.");
+ } finally {
+ releaseBassBoost();
+ terminateListenerLooper();
+ }
+ }
+ assertEquals("parameter change not received",
+ BassBoost.PARAM_STRENGTH, mChangedParameter);
+ }
+
+ //-----------------------------------------------------------------
+ // private methods
+ //----------------------------------
+
+ private void getBassBoost(int session) {
+ if (mBassBoost == null || session != mSession) {
+ if (session != mSession && mBassBoost != null) {
+ mBassBoost.release();
+ mBassBoost = null;
+ }
+ try {
+ mBassBoost = new BassBoost(0, session);
+ mSession = session;
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "getBassBoost() BassBoost not found exception: "+e);
+ } catch (UnsupportedOperationException e) {
+ Log.e(TAG, "getBassBoost() Effect library not loaded exception: "+e);
+ }
+ }
+ assertNotNull("could not create mBassBoost", mBassBoost);
+ }
+
+ private void releaseBassBoost() {
+ if (mBassBoost != null) {
+ mBassBoost.release();
+ mBassBoost = null;
+ }
+ }
+
+ // Initializes the bassboot listener looper
+ class ListenerThread extends Thread {
+ boolean mControl;
+ boolean mEnable;
+ boolean mParameter;
+
+ public ListenerThread(boolean control, boolean enable, boolean parameter) {
+ super();
+ mControl = control;
+ mEnable = enable;
+ mParameter = parameter;
+ }
+ }
+
+ private void createListenerLooper(boolean control, boolean enable, boolean parameter) {
+ mInitialized = false;
+ new ListenerThread(control, enable, parameter) {
+ @Override
+ public void run() {
+ // Set up a looper
+ Looper.prepare();
+
+ // Save the looper so that we can terminate this thread
+ // after we are done with it.
+ mLooper = Looper.myLooper();
+
+ mBassBoost2 = new BassBoost(0, 0);
+ assertNotNull("could not create bassboot2", mBassBoost2);
+
+ if (mControl) {
+ mBassBoost2.setControlStatusListener(
+ new AudioEffect.OnControlStatusChangeListener() {
+ public void onControlStatusChange(
+ AudioEffect effect, boolean controlGranted) {
+ synchronized(mLock) {
+ if (effect == mBassBoost2) {
+ mHasControl = controlGranted;
+ mLock.notify();
+ }
+ }
+ }
+ });
+ }
+ if (mEnable) {
+ mBassBoost2.setEnableStatusListener(
+ new AudioEffect.OnEnableStatusChangeListener() {
+ public void onEnableStatusChange(AudioEffect effect, boolean enabled) {
+ synchronized(mLock) {
+ if (effect == mBassBoost2) {
+ mIsEnabled = enabled;
+ mLock.notify();
+ }
+ }
+ }
+ });
+ }
+ if (mParameter) {
+ mBassBoost2.setParameterListener(new BassBoost.OnParameterChangeListener() {
+ public void onParameterChange(BassBoost effect, int status,
+ int param, short value)
+ {
+ synchronized(mLock) {
+ if (effect == mBassBoost2) {
+ mChangedParameter = param;
+ mLock.notify();
+ }
+ }
+ }
+ });
+ }
+
+ synchronized(mLock) {
+ mInitialized = true;
+ mLock.notify();
+ }
+ Looper.loop(); // Blocks forever until Looper.quit() is called.
+ }
+ }.start();
+ }
+
+ // Terminates the listener looper thread.
+ private void terminateListenerLooper() {
+ if (mBassBoost2 != null) {
+ mBassBoost2.release();
+ mBassBoost2 = null;
+ }
+ if (mLooper != null) {
+ mLooper.quit();
+ mLooper = null;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/tests/tests/media/src/android/media/cts/CamcorderProfileTest.java b/tests/tests/media/src/android/media/cts/CamcorderProfileTest.java
new file mode 100644
index 0000000..b94da11
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/CamcorderProfileTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2010 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.media.cts;
+
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+
+import android.hardware.Camera;
+import android.media.CamcorderProfile;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.util.List;
+
+@TestTargetClass(CamcorderProfile.class)
+public class CamcorderProfileTest extends AndroidTestCase {
+
+ private static final String TAG = "CamcorderProfileTest";
+
+ private void checkProfile(CamcorderProfile profile) {
+ Log.v(TAG, String.format("profile: duration=%d, quality=%d, " +
+ "fileFormat=%d, videoCodec=%d, videoBitRate=%d, videoFrameRate=%d, " +
+ "videoFrameWidth=%d, videoFrameHeight=%d, audioCodec=%d, " +
+ "audioBitRate=%d, audioSampleRate=%d, audioChannels=%d",
+ profile.duration,
+ profile.quality,
+ profile.fileFormat,
+ profile.videoCodec,
+ profile.videoBitRate,
+ profile.videoFrameRate,
+ profile.videoFrameWidth,
+ profile.videoFrameHeight,
+ profile.audioCodec,
+ profile.audioBitRate,
+ profile.audioSampleRate,
+ profile.audioChannels));
+ assertTrue(profile.duration > 0);
+ assertTrue(profile.quality == CamcorderProfile.QUALITY_LOW ||
+ profile.quality == CamcorderProfile.QUALITY_HIGH);
+ assertTrue(profile.videoBitRate > 0);
+ assertTrue(profile.videoFrameRate > 0);
+ assertTrue(profile.videoFrameWidth > 0);
+ assertTrue(profile.videoFrameHeight > 0);
+ assertTrue(profile.audioBitRate > 0);
+ assertTrue(profile.audioSampleRate > 0);
+ assertTrue(profile.audioChannels > 0);
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "get",
+ args = {int.class}
+ )
+ })
+ public void testGet() {
+ CamcorderProfile lowProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_LOW);
+ CamcorderProfile highProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
+ checkProfile(lowProfile);
+ checkProfile(highProfile);
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "get",
+ args = {int.class, int.class}
+ )
+ })
+ public void testGetWithId() {
+ int nCamera = Camera.getNumberOfCameras();
+ for (int id = 0; id < nCamera; id++) {
+ CamcorderProfile lowProfile = CamcorderProfile.get(id,
+ CamcorderProfile.QUALITY_LOW);
+ CamcorderProfile highProfile = CamcorderProfile.get(id,
+ CamcorderProfile.QUALITY_HIGH);
+ checkProfile(lowProfile);
+ checkProfile(highProfile);
+ }
+ }
+}
diff --git a/tests/tests/media/src/android/media/cts/CameraProfileTest.java b/tests/tests/media/src/android/media/cts/CameraProfileTest.java
new file mode 100644
index 0000000..72cd296a
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/CameraProfileTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2010 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.media.cts;
+
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+
+import android.hardware.Camera;
+import android.media.CameraProfile;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.util.List;
+
+@TestTargetClass(CameraProfile.class)
+public class CameraProfileTest extends AndroidTestCase {
+
+ private static final String TAG = "CameraProfileTest";
+
+ private void checkQuality(int low, int mid, int high) {
+ Log.v(TAG, "low = " + low + ", mid = " + mid + ", high = " + high);
+ assertTrue(low >= 0 && low <= 100);
+ assertTrue(mid >= 0 && mid <= 100);
+ assertTrue(high >= 0 && high <= 100);
+ assertTrue(low <= mid && mid <= high);
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getJpegEncodingQualityParameter",
+ args = {int.class}
+ )
+ })
+ public void testGetImageEncodingQualityParameter() {
+ int low = CameraProfile.getJpegEncodingQualityParameter(CameraProfile.QUALITY_LOW);
+ int mid = CameraProfile.getJpegEncodingQualityParameter(CameraProfile.QUALITY_MEDIUM);
+ int high = CameraProfile.getJpegEncodingQualityParameter(CameraProfile.QUALITY_HIGH);
+ checkQuality(low, mid, high);
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getJpegEncodingQualityParameter",
+ args = {int.class, int.class}
+ )
+ })
+ public void testGetWithId() {
+ int nCamera = Camera.getNumberOfCameras();
+ for (int id = 0; id < nCamera; id++) {
+ int low = CameraProfile.getJpegEncodingQualityParameter(id, CameraProfile.QUALITY_LOW);
+ int mid = CameraProfile.getJpegEncodingQualityParameter(id, CameraProfile.QUALITY_MEDIUM);
+ int high = CameraProfile.getJpegEncodingQualityParameter(id, CameraProfile.QUALITY_HIGH);
+ checkQuality(low, mid, high);
+ }
+ }
+}
diff --git a/tests/tests/media/src/android/media/cts/EnvReverbTest.java b/tests/tests/media/src/android/media/cts/EnvReverbTest.java
new file mode 100644
index 0000000..fe7baf9
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/EnvReverbTest.java
@@ -0,0 +1,698 @@
+/*
+ * Copyright (C) 2010 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.media.cts;
+
+import android.media.audiofx.AudioEffect;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.audiofx.EnvironmentalReverb;
+import android.os.Looper;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+
+@TestTargetClass(EnvironmentalReverb.class)
+public class EnvReverbTest extends AndroidTestCase {
+
+ private String TAG = "EnvReverbTest";
+ private final static int MILLIBEL_TOLERANCE = 100; // +/-1dB
+ private final static float DELAY_TOLERANCE = 1.05f; // 5%
+ private final static float RATIO_TOLERANCE = 1.05f; // 5%
+
+ private EnvironmentalReverb mReverb = null;
+ private EnvironmentalReverb mReverb2 = null;
+ private int mSession = -1;
+ private boolean mHasControl = false;
+ private boolean mIsEnabled = false;
+ private int mChangedParameter = -1;
+ private boolean mInitialized = false;
+ private Looper mLooper = null;
+ private final Object mLock = new Object();
+
+
+ //-----------------------------------------------------------------
+ // ENVIRONMENTAL REVERB TESTS:
+ //----------------------------------
+
+ //-----------------------------------------------------------------
+ // 0 - constructor
+ //----------------------------------
+
+ //Test case 0.0: test constructor and release
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "EnvironmentalReverb",
+ args = {int.class, int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getId",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "release",
+ args = {}
+ )
+ })
+ public void test0_0ConstructorAndRelease() throws Exception {
+ EnvironmentalReverb envReverb = null;
+ try {
+ envReverb = new EnvironmentalReverb(0, 0);
+ assertNotNull("could not create EnvironmentalReverb", envReverb);
+ try {
+ assertTrue("invalid effect ID", (envReverb.getId() != 0));
+ } catch (IllegalStateException e) {
+ fail("EnvironmentalReverb not initialized");
+ }
+ } catch (IllegalArgumentException e) {
+ fail("EnvironmentalReverb not found");
+ } catch (UnsupportedOperationException e) {
+ fail("Effect library not loaded");
+ } finally {
+ if (envReverb != null) {
+ envReverb.release();
+ }
+ }
+ }
+
+
+ //-----------------------------------------------------------------
+ // 1 - get/set parameters
+ //----------------------------------
+
+ //Test case 1.0: test room level and room HF level
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setRoomLevel",
+ args = {short.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getRoomLevel",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setRoomHFLevel",
+ args = {short.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getRoomHFLevel",
+ args = {}
+ )
+ })
+ public void test1_0Room() throws Exception {
+ getReverb(0);
+ try {
+ short level = mReverb.getRoomLevel();
+ level = (short)((level == 0) ? -1000 : 0);
+ mReverb.setRoomLevel(level);
+ short level2 = mReverb.getRoomLevel();
+ assertTrue("got incorrect room level",
+ (level2 > (level - MILLIBEL_TOLERANCE)) &&
+ (level2 < (level + MILLIBEL_TOLERANCE)));
+
+ level = mReverb.getRoomHFLevel();
+ level = (short)((level == 0) ? -1000 : 0);
+ mReverb.setRoomHFLevel(level);
+ level2 = mReverb.getRoomHFLevel();
+ assertTrue("got incorrect room HF level",
+ (level2 > (level - MILLIBEL_TOLERANCE)) &&
+ (level2 < (level + MILLIBEL_TOLERANCE)));
+
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("get parameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("get parameter() called in wrong state");
+ } finally {
+ releaseReverb();
+ }
+ }
+
+ //Test case 1.1: test decay time and ratio
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setDecayTime",
+ args = {int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getDecayTime",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setDecayHFRatio",
+ args = {short.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getDecayHFRatio",
+ args = {}
+ )
+ })
+ public void test1_1Decay() throws Exception {
+ getReverb(0);
+ try {
+ int time = mReverb.getDecayTime();
+ time = (time == 500) ? 1000 : 500;
+ mReverb.setDecayTime(time);
+ int time2 = mReverb.getDecayTime();
+ assertTrue("got incorrect decay time",
+ ((float)time2 > (float)(time / DELAY_TOLERANCE)) &&
+ ((float)time2 < (float)(time * DELAY_TOLERANCE)));
+ short ratio = mReverb.getDecayHFRatio();
+ ratio = (short)((ratio == 500) ? 1000 : 500);
+ mReverb.setDecayHFRatio(ratio);
+ short ratio2 = mReverb.getDecayHFRatio();
+ assertTrue("got incorrect decay HF ratio",
+ ((float)ratio2 > (float)(ratio / RATIO_TOLERANCE)) &&
+ ((float)ratio2 < (float)(ratio * RATIO_TOLERANCE)));
+
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("get parameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("get parameter() called in wrong state");
+ } finally {
+ releaseReverb();
+ }
+ }
+
+
+ //Test case 1.2: test reverb level and delay
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setReverbLevel",
+ args = {short.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getReverbLevel",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setReverbDelay",
+ args = {int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getReverbDelay",
+ args = {}
+ )
+ })
+ public void test1_2Reverb() throws Exception {
+ getReverb(0);
+ try {
+ short level = mReverb.getReverbLevel();
+ level = (short)((level == 0) ? -1000 : 0);
+ mReverb.setReverbLevel(level);
+ short level2 = mReverb.getReverbLevel();
+ assertTrue("got incorrect reverb level",
+ (level2 > (level - MILLIBEL_TOLERANCE)) &&
+ (level2 < (level + MILLIBEL_TOLERANCE)));
+
+// FIXME:uncomment actual test when early reflections are implemented in the reverb
+// int time = mReverb.getReverbDelay();
+// mReverb.setReverbDelay(time);
+// int time2 = mReverb.getReverbDelay();
+// assertTrue("got incorrect reverb delay",
+// ((float)time2 > (float)(time / DELAY_TOLERANCE)) &&
+// ((float)time2 < (float)(time * DELAY_TOLERANCE)));
+ mReverb.setReverbDelay(0);
+ int time2 = mReverb.getReverbDelay();
+ assertEquals("got incorrect reverb delay", mReverb.getReverbDelay(), 0);
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("get parameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("get parameter() called in wrong state");
+ } finally {
+ releaseReverb();
+ }
+ }
+
+ //Test case 1.3: test early reflections level and delay
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setReflectionsLevel",
+ args = {short.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getReflectionsLevel",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setReflectionsDelay",
+ args = {int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getReflectionsDelay",
+ args = {}
+ )
+ })
+ public void test1_3Reflections() throws Exception {
+ getReverb(0);
+ try {
+// FIXME:uncomment actual test when early reflections are implemented in the reverb
+// short level = mReverb.getReflectionsLevel();
+// level = (short)((level == 0) ? -1000 : 0);
+// mReverb.setReflectionsLevel(level);
+// short level2 = mReverb.getReflectionsLevel();
+// assertTrue("got incorrect reflections level",
+// (level2 > (level - MILLIBEL_TOLERANCE)) &&
+// (level2 < (level + MILLIBEL_TOLERANCE)));
+//
+// int time = mReverb.getReflectionsDelay();
+// time = (time == 20) ? 0 : 20;
+// mReverb.setReflectionsDelay(time);
+// int time2 = mReverb.getReflectionsDelay();
+// assertTrue("got incorrect reflections delay",
+// ((float)time2 > (float)(time / DELAY_TOLERANCE)) &&
+// ((float)time2 < (float)(time * DELAY_TOLERANCE)));
+ mReverb.setReflectionsLevel((short) 0);
+ assertEquals("got incorrect reverb delay",
+ mReverb.getReflectionsLevel(), (short) 0);
+ mReverb.setReflectionsDelay(0);
+ assertEquals("got incorrect reverb delay",
+ mReverb.getReflectionsDelay(), 0);
+
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("get parameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("get parameter() called in wrong state");
+ } finally {
+ releaseReverb();
+ }
+ }
+
+ //Test case 1.4: test diffusion and density
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setDiffusion",
+ args = {short.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getDiffusion",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setDensity",
+ args = {short.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getDensity",
+ args = {}
+ )
+ })
+ public void test1_4DiffusionAndDensity() throws Exception {
+ getReverb(0);
+ try {
+ short ratio = mReverb.getDiffusion();
+ ratio = (short)((ratio == 500) ? 1000 : 500);
+ mReverb.setDiffusion(ratio);
+ short ratio2 = mReverb.getDiffusion();
+ assertTrue("got incorrect diffusion",
+ ((float)ratio2 > (float)(ratio / RATIO_TOLERANCE)) &&
+ ((float)ratio2 < (float)(ratio * RATIO_TOLERANCE)));
+
+ ratio = mReverb.getDensity();
+ ratio = (short)((ratio == 500) ? 1000 : 500);
+ mReverb.setDensity(ratio);
+ ratio2 = mReverb.getDensity();
+ assertTrue("got incorrect density",
+ ((float)ratio2 > (float)(ratio / RATIO_TOLERANCE)) &&
+ ((float)ratio2 < (float)(ratio * RATIO_TOLERANCE)));
+
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("get parameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("get parameter() called in wrong state");
+ } finally {
+ releaseReverb();
+ }
+ }
+
+ //Test case 1.5: test properties
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getProperties",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setProperties",
+ args = {EnvironmentalReverb.Settings.class}
+ )
+ })
+ public void test1_5Properties() throws Exception {
+ getReverb(0);
+ try {
+ EnvironmentalReverb.Settings settings = mReverb.getProperties();
+ String str = settings.toString();
+ settings = new EnvironmentalReverb.Settings(str);
+ short level = (short)((settings.roomLevel == 0) ? -1000 : 0);
+ settings.roomLevel = level;
+ mReverb.setProperties(settings);
+ settings = mReverb.getProperties();
+ assertTrue("setProperties failed",
+ (settings.roomLevel >= (level - MILLIBEL_TOLERANCE)) &&
+ (settings.roomLevel <= (level + MILLIBEL_TOLERANCE)));
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("get parameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("get parameter() called in wrong state");
+ } finally {
+ releaseReverb();
+ }
+ }
+
+ //-----------------------------------------------------------------
+ // 2 - Effect enable/disable
+ //----------------------------------
+
+ //Test case 2.0: test setEnabled() and getEnabled() in valid state
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnabled",
+ args = {boolean.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getEnabled",
+ args = {}
+ )
+ })
+ public void test2_0SetEnabledGetEnabled() throws Exception {
+ getReverb(0);
+ try {
+ mReverb.setEnabled(true);
+ assertTrue("invalid state from getEnabled", mReverb.getEnabled());
+ mReverb.setEnabled(false);
+ assertFalse("invalid state to getEnabled", mReverb.getEnabled());
+ } catch (IllegalStateException e) {
+ fail("setEnabled() in wrong state");
+ } finally {
+ releaseReverb();
+ }
+ }
+
+ //Test case 2.1: test setEnabled() throws exception after release
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "release",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnabled",
+ args = {boolean.class}
+ )
+ })
+ public void test2_1SetEnabledAfterRelease() throws Exception {
+ getReverb(0);
+ mReverb.release();
+ try {
+ mReverb.setEnabled(true);
+ fail("setEnabled() processed after release()");
+ } catch (IllegalStateException e) {
+ // test passed
+ } finally {
+ releaseReverb();
+ }
+ }
+
+ //-----------------------------------------------------------------
+ // 3 priority and listeners
+ //----------------------------------
+
+ //Test case 3.0: test control status listener
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setControlStatusListener",
+ args = {AudioEffect.OnControlStatusChangeListener.class}
+ )
+ })
+ public void test3_0ControlStatusListener() throws Exception {
+ mHasControl = true;
+ createListenerLooper(true, false, false);
+ synchronized(mLock) {
+ try {
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Looper creation: wait was interrupted.");
+ }
+ }
+ assertTrue(mInitialized);
+ synchronized(mLock) {
+ try {
+ getReverb(0);
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Create second effect: wait was interrupted.");
+ } finally {
+ releaseReverb();
+ terminateListenerLooper();
+ }
+ }
+ assertFalse("effect control not lost by effect1", mHasControl);
+ }
+
+ //Test case 3.1: test enable status listener
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnableStatusListener",
+ args = {AudioEffect.OnEnableStatusChangeListener.class}
+ )
+ })
+ public void test3_1EnableStatusListener() throws Exception {
+ createListenerLooper(false, true, false);
+ synchronized(mLock) {
+ try {
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Looper creation: wait was interrupted.");
+ }
+ }
+ assertTrue(mInitialized);
+ mReverb2.setEnabled(true);
+ mIsEnabled = true;
+ getReverb(0);
+ synchronized(mLock) {
+ try {
+ mReverb.setEnabled(false);
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Create second effect: wait was interrupted.");
+ } finally {
+ releaseReverb();
+ terminateListenerLooper();
+ }
+ }
+ assertFalse("enable status not updated", mIsEnabled);
+ }
+
+ //Test case 3.2: test parameter changed listener
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setParameterListener",
+ args = {EnvironmentalReverb.OnParameterChangeListener.class}
+ )
+ })
+ public void test3_2ParameterChangedListener() throws Exception {
+ createListenerLooper(false, false, true);
+ synchronized(mLock) {
+ try {
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Looper creation: wait was interrupted.");
+ }
+ }
+ assertTrue(mInitialized);
+ getReverb(0);
+ synchronized(mLock) {
+ try {
+ mChangedParameter = -1;
+ mReverb.setRoomLevel((short)0);
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Create second effect: wait was interrupted.");
+ } finally {
+ releaseReverb();
+ terminateListenerLooper();
+ }
+ }
+ assertEquals("parameter change not received",
+ EnvironmentalReverb.PARAM_ROOM_LEVEL, mChangedParameter);
+ }
+
+ //-----------------------------------------------------------------
+ // private methods
+ //----------------------------------
+
+ private void getReverb(int session) {
+ if (mReverb == null || session != mSession) {
+ if (session != mSession && mReverb != null) {
+ mReverb.release();
+ mReverb = null;
+ }
+ try {
+ mReverb = new EnvironmentalReverb(0, session);
+ mSession = session;
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "getReverb() EnvironmentalReverb not found exception: "+e);
+ } catch (UnsupportedOperationException e) {
+ Log.e(TAG, "getReverb() Effect library not loaded exception: "+e);
+ }
+ }
+ assertNotNull("could not create mReverb", mReverb);
+ }
+
+ private void releaseReverb() {
+ if (mReverb != null) {
+ mReverb.release();
+ mReverb = null;
+ }
+ }
+
+ // Initializes the reverb listener looper
+ class ListenerThread extends Thread {
+ boolean mControl;
+ boolean mEnable;
+ boolean mParameter;
+
+ public ListenerThread(boolean control, boolean enable, boolean parameter) {
+ super();
+ mControl = control;
+ mEnable = enable;
+ mParameter = parameter;
+ }
+ }
+
+ private void createListenerLooper(boolean control, boolean enable, boolean parameter) {
+ mInitialized = false;
+ new ListenerThread(control, enable, parameter) {
+ @Override
+ public void run() {
+ // Set up a looper
+ Looper.prepare();
+
+ // Save the looper so that we can terminate this thread
+ // after we are done with it.
+ mLooper = Looper.myLooper();
+
+ mReverb2 = new EnvironmentalReverb(0, 0);
+ assertNotNull("could not create reverb2", mReverb2);
+
+ if (mControl) {
+ mReverb2.setControlStatusListener(
+ new AudioEffect.OnControlStatusChangeListener() {
+ public void onControlStatusChange(
+ AudioEffect effect, boolean controlGranted) {
+ synchronized(mLock) {
+ if (effect == mReverb2) {
+ mHasControl = controlGranted;
+ mLock.notify();
+ }
+ }
+ }
+ });
+ }
+ if (mEnable) {
+ mReverb2.setEnableStatusListener(
+ new AudioEffect.OnEnableStatusChangeListener() {
+ public void onEnableStatusChange(AudioEffect effect, boolean enabled) {
+ synchronized(mLock) {
+ if (effect == mReverb2) {
+ mIsEnabled = enabled;
+ mLock.notify();
+ }
+ }
+ }
+ });
+ }
+ if (mParameter) {
+ mReverb2.setParameterListener(new EnvironmentalReverb.OnParameterChangeListener() {
+ public void onParameterChange(EnvironmentalReverb effect,
+ int status, int param, int value)
+ {
+ synchronized(mLock) {
+ if (effect == mReverb2) {
+ mChangedParameter = param;
+ mLock.notify();
+ }
+ }
+ }
+ });
+ }
+
+ synchronized(mLock) {
+ mInitialized = true;
+ mLock.notify();
+ }
+ Looper.loop(); // Blocks forever until Looper.quit() is called.
+ }
+ }.start();
+ }
+
+ // Terminates the listener looper thread.
+ private void terminateListenerLooper() {
+ if (mReverb2 != null) {
+ mReverb2.release();
+ mReverb2 = null;
+ }
+ if (mLooper != null) {
+ mLooper.quit();
+ mLooper = null;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/tests/tests/media/src/android/media/cts/EqualizerTest.java b/tests/tests/media/src/android/media/cts/EqualizerTest.java
new file mode 100644
index 0000000..4b63828
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/EqualizerTest.java
@@ -0,0 +1,600 @@
+/*
+ * Copyright (C) 2010 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.media.cts;
+
+import android.media.audiofx.AudioEffect;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.audiofx.Equalizer;
+import android.os.Looper;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+
+@TestTargetClass(Equalizer.class)
+public class EqualizerTest extends AndroidTestCase {
+
+ private String TAG = "EqualizerTest";
+ private final static int MIN_NUMBER_OF_BANDS = 4;
+ private final static int MAX_LEVEL_RANGE_LOW = -1200; // -12dB
+ private final static int MIN_LEVEL_RANGE_HIGH = 1200; // +12dB
+ private final static int TEST_FREQUENCY_MILLIHERTZ = 1000000; // 1kHz
+ private final static int MIN_NUMBER_OF_PRESETS = 0;
+ private final static float TOLERANCE = 100; // +/-1dB
+
+ private Equalizer mEqualizer = null;
+ private Equalizer mEqualizer2 = null;
+ private int mSession = -1;
+ private boolean mHasControl = false;
+ private boolean mIsEnabled = false;
+ private int mChangedParameter = -1;
+ private boolean mInitialized = false;
+ private Looper mLooper = null;
+ private final Object mLock = new Object();
+
+
+ //-----------------------------------------------------------------
+ // EQUALIZER TESTS:
+ //----------------------------------
+
+ //-----------------------------------------------------------------
+ // 0 - constructor
+ //----------------------------------
+
+ //Test case 0.0: test constructor and release
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "Equalizer",
+ args = {int.class, int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getId",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "release",
+ args = {}
+ )
+ })
+ public void test0_0ConstructorAndRelease() throws Exception {
+ Equalizer eq = null;
+ try {
+ eq = new Equalizer(0, 0);
+ assertNotNull("could not create Equalizer", eq);
+ try {
+ assertTrue("invalid effect ID", (eq.getId() != 0));
+ } catch (IllegalStateException e) {
+ fail("Equalizer not initialized");
+ }
+ } catch (IllegalArgumentException e) {
+ fail("Equalizer not found");
+ } catch (UnsupportedOperationException e) {
+ fail("Effect library not loaded");
+ } finally {
+ if (eq != null) {
+ eq.release();
+ }
+ }
+ }
+
+
+ //-----------------------------------------------------------------
+ // 1 - get/set parameters
+ //----------------------------------
+
+ //Test case 1.0: test setBandLevel() and getBandLevel()
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getNumberOfBands",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getBandLevelRange",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setBandLevel",
+ args = {short.class, short.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getBandLevel",
+ args = {short.class}
+ )
+ })
+ public void test1_0BandLevel() throws Exception {
+ getEqualizer(0);
+ try {
+ short numBands = mEqualizer.getNumberOfBands();
+ assertTrue("not enough bands", numBands >= MIN_NUMBER_OF_BANDS);
+
+ short[] levelRange = mEqualizer.getBandLevelRange();
+ assertTrue("min level too high", levelRange[0] <= MAX_LEVEL_RANGE_LOW);
+ assertTrue("max level too low", levelRange[1] >= MIN_LEVEL_RANGE_HIGH);
+
+ mEqualizer.setBandLevel((short)0, levelRange[1]);
+ short level = mEqualizer.getBandLevel((short)0);
+ // allow +/- TOLERANCE margin on actual level compared to requested level
+ assertTrue("setBandLevel failed",
+ (level >= (levelRange[1] - TOLERANCE)) &&
+ (level <= (levelRange[1] + TOLERANCE)));
+
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("get parameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("get parameter() called in wrong state");
+ } finally {
+ releaseEqualizer();
+ }
+ }
+
+ //Test case 1.1: test band frequency
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getBand",
+ args = {int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getBandFreqRange",
+ args = {short.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getCenterFreq",
+ args = {short.class}
+ )
+ })
+ public void test1_1BandFrequency() throws Exception {
+ getEqualizer(0);
+ try {
+ short band = mEqualizer.getBand(TEST_FREQUENCY_MILLIHERTZ);
+ assertTrue("getBand failed", band >= 0);
+ int[] freqRange = mEqualizer.getBandFreqRange(band);
+ assertTrue("getBandFreqRange failed",
+ (freqRange[0] <= TEST_FREQUENCY_MILLIHERTZ) &&
+ (freqRange[1] >= TEST_FREQUENCY_MILLIHERTZ));
+ int freq = mEqualizer.getCenterFreq(band);
+ assertTrue("getCenterFreq failed",
+ (freqRange[0] <= freq) && (freqRange[1] >= freq));
+
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("get parameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("get parameter() called in wrong state");
+ } finally {
+ releaseEqualizer();
+ }
+ }
+
+ //Test case 1.2: test presets
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getNumberOfPresets",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "usePreset",
+ args = {short.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getCurrentPreset",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getPresetName",
+ args = {short.class}
+ )
+ })
+ public void test1_2Presets() throws Exception {
+ getEqualizer(0);
+ try {
+ short numPresets = mEqualizer.getNumberOfPresets();
+ assertTrue("getNumberOfPresets failed", numPresets >= MIN_NUMBER_OF_PRESETS);
+ if (numPresets > 0) {
+ mEqualizer.usePreset((short)(numPresets - 1));
+ short preset = mEqualizer.getCurrentPreset();
+ assertEquals("usePreset failed", preset, (short)(numPresets - 1));
+ String name = mEqualizer.getPresetName(preset);
+ assertNotNull("getPresetName failed", name);
+ }
+
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("get parameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("get parameter() called in wrong state");
+ } finally {
+ releaseEqualizer();
+ }
+ }
+
+ //Test case 1.3: test properties
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getProperties",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setProperties",
+ args = {Equalizer.Settings.class}
+ )
+ })
+ public void test1_3Properties() throws Exception {
+ getEqualizer(0);
+ try {
+ Equalizer.Settings settings = mEqualizer.getProperties();
+ assertTrue("no enough bands", settings.numBands >= MIN_NUMBER_OF_BANDS);
+ short newLevel = 0;
+ if (settings.bandLevels[0] == 0) {
+ newLevel = -600;
+ }
+ String str = settings.toString();
+ settings = new Equalizer.Settings(str);
+ settings.curPreset = (short)-1;
+ settings.bandLevels[0] = newLevel;
+ mEqualizer.setProperties(settings);
+ settings = mEqualizer.getProperties();
+ assertTrue("setProperties failed",
+ (settings.bandLevels[0] >= (newLevel - TOLERANCE)) &&
+ (settings.bandLevels[0] <= (newLevel + TOLERANCE)));
+
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("get parameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("get parameter() called in wrong state");
+ } finally {
+ releaseEqualizer();
+ }
+ }
+
+ //Test case 1.4: test setBandLevel() throws exception after release
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "release",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setBandLevel",
+ args = {short.class, short.class}
+ )
+ })
+ public void test1_4SetBandLevelAfterRelease() throws Exception {
+
+ getEqualizer(0);
+ mEqualizer.release();
+ try {
+ mEqualizer.setBandLevel((short)0, (short)0);
+ } catch (IllegalStateException e) {
+ // test passed
+ } finally {
+ releaseEqualizer();
+ }
+ }
+
+ //-----------------------------------------------------------------
+ // 2 - Effect enable/disable
+ //----------------------------------
+
+ //Test case 2.0: test setEnabled() and getEnabled() in valid state
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnabled",
+ args = {boolean.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getEnabled",
+ args = {}
+ )
+ })
+ public void test2_0SetEnabledGetEnabled() throws Exception {
+ getEqualizer(0);
+ try {
+ mEqualizer.setEnabled(true);
+ assertTrue("invalid state from getEnabled", mEqualizer.getEnabled());
+ mEqualizer.setEnabled(false);
+ assertFalse("invalid state to getEnabled", mEqualizer.getEnabled());
+
+ } catch (IllegalStateException e) {
+ fail("setEnabled() in wrong state");
+ } finally {
+ releaseEqualizer();
+ }
+ }
+
+ //Test case 2.1: test setEnabled() throws exception after release
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "release",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnabled",
+ args = {boolean.class}
+ )
+ })
+ public void test2_1SetEnabledAfterRelease() throws Exception {
+
+ getEqualizer(0);
+ mEqualizer.release();
+ try {
+ mEqualizer.setEnabled(true);
+ } catch (IllegalStateException e) {
+ // test passed
+ } finally {
+ releaseEqualizer();
+ }
+ }
+
+ //-----------------------------------------------------------------
+ // 3 priority and listeners
+ //----------------------------------
+
+ //Test case 3.0: test control status listener
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setControlStatusListener",
+ args = {AudioEffect.OnControlStatusChangeListener.class}
+ )
+ })
+ public void test3_0ControlStatusListener() throws Exception {
+ mHasControl = true;
+ createListenerLooper(true, false, false);
+ synchronized(mLock) {
+ try {
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Looper creation: wait was interrupted.");
+ }
+ }
+ assertTrue(mInitialized);
+ synchronized(mLock) {
+ try {
+ getEqualizer(0);
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Create second effect: wait was interrupted.");
+ } finally {
+ releaseEqualizer();
+ terminateListenerLooper();
+ }
+ }
+ assertFalse("effect control not lost by effect1", mHasControl);
+ }
+
+ //Test case 3.1: test enable status listener
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnableStatusListener",
+ args = {AudioEffect.OnEnableStatusChangeListener.class}
+ )
+ })
+ public void test3_1EnableStatusListener() throws Exception {
+ createListenerLooper(false, true, false);
+ synchronized(mLock) {
+ try {
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Looper creation: wait was interrupted.");
+ }
+ }
+ assertTrue(mInitialized);
+ mEqualizer2.setEnabled(true);
+ mIsEnabled = true;
+ getEqualizer(0);
+ synchronized(mLock) {
+ try {
+ mEqualizer.setEnabled(false);
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Create second effect: wait was interrupted.");
+ } finally {
+ releaseEqualizer();
+ terminateListenerLooper();
+ }
+ }
+ assertFalse("enable status not updated", mIsEnabled);
+ }
+
+ //Test case 3.2: test parameter changed listener
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setParameterListener",
+ args = {Equalizer.OnParameterChangeListener.class}
+ )
+ })
+ public void test3_2ParameterChangedListener() throws Exception {
+ createListenerLooper(false, false, true);
+ synchronized(mLock) {
+ try {
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Looper creation: wait was interrupted.");
+ }
+ }
+ assertTrue(mInitialized);
+ getEqualizer(0);
+ synchronized(mLock) {
+ try {
+ mChangedParameter = -1;
+ mEqualizer.setBandLevel((short)0, (short)0);
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Create second effect: wait was interrupted.");
+ } finally {
+ releaseEqualizer();
+ terminateListenerLooper();
+ }
+ }
+ assertEquals("parameter change not received",
+ Equalizer.PARAM_BAND_LEVEL, mChangedParameter);
+ }
+
+ //-----------------------------------------------------------------
+ // private methods
+ //----------------------------------
+
+ private void getEqualizer(int session) {
+ if (mEqualizer == null || session != mSession) {
+ if (session != mSession && mEqualizer != null) {
+ mEqualizer.release();
+ mEqualizer = null;
+ }
+ try {
+ mEqualizer = new Equalizer(0, session);
+ mSession = session;
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "getEqualizer() Equalizer not found exception: "+e);
+ } catch (UnsupportedOperationException e) {
+ Log.e(TAG, "getEqualizer() Effect library not loaded exception: "+e);
+ }
+ }
+ assertNotNull("could not create mEqualizer", mEqualizer);
+ }
+
+ private void releaseEqualizer() {
+ if (mEqualizer != null) {
+ mEqualizer.release();
+ mEqualizer = null;
+ }
+ }
+
+ // Initializes the equalizer listener looper
+ class ListenerThread extends Thread {
+ boolean mControl;
+ boolean mEnable;
+ boolean mParameter;
+
+ public ListenerThread(boolean control, boolean enable, boolean parameter) {
+ super();
+ mControl = control;
+ mEnable = enable;
+ mParameter = parameter;
+ }
+ }
+
+ private void createListenerLooper(boolean control, boolean enable, boolean parameter) {
+ mInitialized = false;
+ new ListenerThread(control, enable, parameter) {
+ @Override
+ public void run() {
+ // Set up a looper
+ Looper.prepare();
+
+ // Save the looper so that we can terminate this thread
+ // after we are done with it.
+ mLooper = Looper.myLooper();
+
+ mEqualizer2 = new Equalizer(0, 0);
+ assertNotNull("could not create Equalizer2", mEqualizer2);
+
+ if (mControl) {
+ mEqualizer2.setControlStatusListener(
+ new AudioEffect.OnControlStatusChangeListener() {
+ public void onControlStatusChange(
+ AudioEffect effect, boolean controlGranted) {
+ synchronized(mLock) {
+ if (effect == mEqualizer2) {
+ mHasControl = controlGranted;
+ mLock.notify();
+ }
+ }
+ }
+ });
+ }
+ if (mEnable) {
+ mEqualizer2.setEnableStatusListener(
+ new AudioEffect.OnEnableStatusChangeListener() {
+ public void onEnableStatusChange(AudioEffect effect, boolean enabled) {
+ synchronized(mLock) {
+ if (effect == mEqualizer2) {
+ mIsEnabled = enabled;
+ mLock.notify();
+ }
+ }
+ }
+ });
+ }
+ if (mParameter) {
+ mEqualizer2.setParameterListener(new Equalizer.OnParameterChangeListener() {
+ public void onParameterChange(Equalizer effect,
+ int status, int param1, int param2, int value)
+ {
+ synchronized(mLock) {
+ if (effect == mEqualizer2) {
+ mChangedParameter = param1;
+ mLock.notify();
+ }
+ }
+ }
+ });
+ }
+
+ synchronized(mLock) {
+ mInitialized = true;
+ mLock.notify();
+ }
+ Looper.loop(); // Blocks forever until Looper.quit() is called.
+ }
+ }.start();
+ }
+
+ // Terminates the listener looper thread.
+ private void terminateListenerLooper() {
+ if (mEqualizer2 != null) {
+ mEqualizer2.release();
+ mEqualizer2 = null;
+ }
+ if (mLooper != null) {
+ mLooper.quit();
+ mLooper = null;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
index e5dc1ff..db9c5be 100644
--- a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
@@ -38,8 +38,8 @@
private final String OUTPUT_PATH;
private static final int RECORD_TIME = 3000;
- private static final int VIDEO_WIDTH = 320;
- private static final int VIDEO_HEIGHT = 240;
+ private static final int VIDEO_WIDTH = 176;
+ private static final int VIDEO_HEIGHT = 144;
private static final int FRAME_RATE = 15;
private static final long MAX_FILE_SIZE = 5000;
private static final int MAX_DURATION_MSEC = 200;
diff --git a/tests/tests/media/src/android/media/cts/PresetReverbTest.java b/tests/tests/media/src/android/media/cts/PresetReverbTest.java
new file mode 100644
index 0000000..a1b05bd
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/PresetReverbTest.java
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2010 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.media.cts;
+
+import android.media.audiofx.AudioEffect;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.audiofx.PresetReverb;
+import android.os.Looper;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+
+@TestTargetClass(PresetReverb.class)
+public class PresetReverbTest extends AndroidTestCase {
+
+ private String TAG = "PresetReverbTest";
+ private final static short FIRST_PRESET = PresetReverb.PRESET_NONE;
+ private final static short LAST_PRESET = PresetReverb.PRESET_PLATE;
+ private PresetReverb mReverb = null;
+ private PresetReverb mReverb2 = null;
+ private int mSession = -1;
+ private boolean mHasControl = false;
+ private boolean mIsEnabled = false;
+ private int mChangedParameter = -1;
+ private boolean mInitialized = false;
+ private Looper mLooper = null;
+ private final Object mLock = new Object();
+
+
+ //-----------------------------------------------------------------
+ // PRESET REVERB TESTS:
+ //----------------------------------
+
+ //-----------------------------------------------------------------
+ // 0 - constructor
+ //----------------------------------
+
+ //Test case 0.0: test constructor and release
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "PresetReverb",
+ args = {int.class, int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getId",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "release",
+ args = {}
+ )
+ })
+ public void test0_0ConstructorAndRelease() throws Exception {
+ PresetReverb reverb = null;
+ try {
+ reverb = new PresetReverb(0, 0);
+ assertNotNull("could not create PresetReverb", reverb);
+ try {
+ assertTrue("invalid effect ID", (reverb.getId() != 0));
+ } catch (IllegalStateException e) {
+ fail("PresetReverb not initialized");
+ }
+ } catch (IllegalArgumentException e) {
+ fail("PresetReverb not found");
+ } catch (UnsupportedOperationException e) {
+ fail("Effect library not loaded");
+ } finally {
+ if (reverb != null) {
+ reverb.release();
+ }
+ }
+ }
+
+ //-----------------------------------------------------------------
+ // 1 - get/set parameters
+ //----------------------------------
+
+ //Test case 1.0: test presets
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setPreset",
+ args = {short.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getPreset",
+ args = {}
+ )
+ })
+ public void test1_0Presets() throws Exception {
+ getReverb(0);
+ try {
+ for (short preset = FIRST_PRESET;
+ preset <= LAST_PRESET;
+ preset++) {
+ mReverb.setPreset(preset);
+ assertEquals("got incorrect preset", preset, mReverb.getPreset());
+ }
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("get parameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("get parameter() called in wrong state");
+ } finally {
+ releaseReverb();
+ }
+ }
+
+ //Test case 1.1: test properties
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getProperties",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setProperties",
+ args = {PresetReverb.Settings.class}
+ )
+ })
+ public void test1_1Properties() throws Exception {
+ getReverb(0);
+ try {
+ PresetReverb.Settings settings = mReverb.getProperties();
+ String str = settings.toString();
+ settings = new PresetReverb.Settings(str);
+ short preset = (settings.preset == PresetReverb.PRESET_SMALLROOM) ?
+ PresetReverb.PRESET_MEDIUMROOM : PresetReverb.PRESET_SMALLROOM;
+ settings.preset = preset;
+ mReverb.setProperties(settings);
+ settings = mReverb.getProperties();
+ assertEquals("setProperties failed", settings.preset, preset);
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("get parameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("get parameter() called in wrong state");
+ } finally {
+ releaseReverb();
+ }
+ }
+
+ //-----------------------------------------------------------------
+ // 2 - Effect enable/disable
+ //----------------------------------
+
+ //Test case 2.0: test setEnabled() and getEnabled() in valid state
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnabled",
+ args = {boolean.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getEnabled",
+ args = {}
+ )
+ })
+ public void test2_0SetEnabledGetEnabled() throws Exception {
+ getReverb(0);
+ try {
+ mReverb.setEnabled(true);
+ assertTrue("invalid state from getEnabled", mReverb.getEnabled());
+ mReverb.setEnabled(false);
+ assertFalse("invalid state to getEnabled", mReverb.getEnabled());
+ } catch (IllegalStateException e) {
+ fail("setEnabled() in wrong state");
+ } finally {
+ releaseReverb();
+ }
+ }
+
+ //Test case 2.1: test setEnabled() throws exception after release
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "release",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnabled",
+ args = {boolean.class}
+ )
+ })
+ public void test2_1SetEnabledAfterRelease() throws Exception {
+ getReverb(0);
+ mReverb.release();
+ try {
+ mReverb.setEnabled(true);
+ } catch (IllegalStateException e) {
+ // test passed
+ } finally {
+ releaseReverb();
+ }
+ }
+
+ //-----------------------------------------------------------------
+ // 3 priority and listeners
+ //----------------------------------
+
+ //Test case 3.0: test control status listener
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setControlStatusListener",
+ args = {AudioEffect.OnControlStatusChangeListener.class}
+ )
+ })
+ public void test3_0ControlStatusListener() throws Exception {
+ mHasControl = true;
+ createListenerLooper(true, false, false);
+ synchronized(mLock) {
+ try {
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Looper creation: wait was interrupted.");
+ }
+ }
+ assertTrue(mInitialized);
+ synchronized(mLock) {
+ try {
+ getReverb(0);
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Create second effect: wait was interrupted.");
+ } finally {
+ releaseReverb();
+ terminateListenerLooper();
+ }
+ }
+ assertFalse("effect control not lost by effect1", mHasControl);
+ }
+
+ //Test case 3.1: test enable status listener
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnableStatusListener",
+ args = {AudioEffect.OnEnableStatusChangeListener.class}
+ )
+ })
+ public void test3_1EnableStatusListener() throws Exception {
+ createListenerLooper(false, true, false);
+ synchronized(mLock) {
+ try {
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Looper creation: wait was interrupted.");
+ }
+ }
+ assertTrue(mInitialized);
+ mReverb2.setEnabled(true);
+ mIsEnabled = true;
+ getReverb(0);
+ synchronized(mLock) {
+ try {
+ mReverb.setEnabled(false);
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Create second effect: wait was interrupted.");
+ } finally {
+ releaseReverb();
+ terminateListenerLooper();
+ }
+ }
+ assertFalse("enable status not updated", mIsEnabled);
+ }
+
+ //Test case 3.2: test parameter changed listener
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setParameterListener",
+ args = {PresetReverb.OnParameterChangeListener.class}
+ )
+ })
+ public void test3_2ParameterChangedListener() throws Exception {
+ createListenerLooper(false, false, true);
+ synchronized(mLock) {
+ try {
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Looper creation: wait was interrupted.");
+ }
+ }
+ assertTrue(mInitialized);
+ getReverb(0);
+ synchronized(mLock) {
+ try {
+ mChangedParameter = -1;
+ mReverb.setPreset(PresetReverb.PRESET_SMALLROOM);
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Create second effect: wait was interrupted.");
+ } finally {
+ releaseReverb();
+ terminateListenerLooper();
+ }
+ }
+ assertEquals("parameter change not received",
+ PresetReverb.PARAM_PRESET, mChangedParameter);
+ }
+
+ //-----------------------------------------------------------------
+ // private methods
+ //----------------------------------
+
+ private void getReverb(int session) {
+ if (mReverb == null || session != mSession) {
+ if (session != mSession && mReverb != null) {
+ mReverb.release();
+ mReverb = null;
+ }
+ try {
+ mReverb = new PresetReverb(0, session);
+ mSession = session;
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "getReverb() PresetReverb not found exception: "+e);
+ } catch (UnsupportedOperationException e) {
+ Log.e(TAG, "getReverb() Effect library not loaded exception: "+e);
+ }
+ }
+ assertNotNull("could not create mReverb", mReverb);
+ }
+
+ private void releaseReverb() {
+ if (mReverb != null) {
+ mReverb.release();
+ mReverb = null;
+ }
+ }
+
+ // Initializes the reverb listener looper
+ class ListenerThread extends Thread {
+ boolean mControl;
+ boolean mEnable;
+ boolean mParameter;
+
+ public ListenerThread(boolean control, boolean enable, boolean parameter) {
+ super();
+ mControl = control;
+ mEnable = enable;
+ mParameter = parameter;
+ }
+ }
+
+ private void createListenerLooper(boolean control, boolean enable, boolean parameter) {
+ mInitialized = false;
+ new ListenerThread(control, enable, parameter) {
+ @Override
+ public void run() {
+ // Set up a looper
+ Looper.prepare();
+
+ // Save the looper so that we can terminate this thread
+ // after we are done with it.
+ mLooper = Looper.myLooper();
+
+ mReverb2 = new PresetReverb(0, 0);
+ assertNotNull("could not create Reverb2", mReverb2);
+
+ if (mControl) {
+ mReverb2.setControlStatusListener(
+ new AudioEffect.OnControlStatusChangeListener() {
+ public void onControlStatusChange(
+ AudioEffect effect, boolean controlGranted) {
+ synchronized(mLock) {
+ if (effect == mReverb2) {
+ mHasControl = controlGranted;
+ mLock.notify();
+ }
+ }
+ }
+ });
+ }
+ if (mEnable) {
+ mReverb2.setEnableStatusListener(
+ new AudioEffect.OnEnableStatusChangeListener() {
+ public void onEnableStatusChange(AudioEffect effect, boolean enabled) {
+ synchronized(mLock) {
+ if (effect == mReverb2) {
+ mIsEnabled = enabled;
+ mLock.notify();
+ }
+ }
+ }
+ });
+ }
+ if (mParameter) {
+ mReverb2.setParameterListener(new PresetReverb.OnParameterChangeListener() {
+ public void onParameterChange(PresetReverb effect,
+ int status, int param, short value)
+ {
+ synchronized(mLock) {
+ if (effect == mReverb2) {
+ mChangedParameter = param;
+ mLock.notify();
+ }
+ }
+ }
+ });
+ }
+
+ synchronized(mLock) {
+ mInitialized = true;
+ mLock.notify();
+ }
+ Looper.loop(); // Blocks forever until Looper.quit() is called.
+ }
+ }.start();
+ }
+
+ // Terminates the listener looper thread.
+ private void terminateListenerLooper() {
+ if (mReverb2 != null) {
+ mReverb2.release();
+ mReverb2 = null;
+ }
+ if (mLooper != null) {
+ mLooper.quit();
+ mLooper = null;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/tests/tests/media/src/android/media/cts/VideoEditorTest.java b/tests/tests/media/src/android/media/cts/VideoEditorTest.java
new file mode 100644
index 0000000..481f4d6
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/VideoEditorTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 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.media.cts;
+
+import com.android.cts.stub.R;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+public class VideoEditorTest extends ActivityInstrumentationTestCase2<MediaStubActivity> {
+
+ public VideoEditorTest() {
+ super(MediaStubActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ //setup for each test case.
+ super.setUp();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ //Test case clean up.
+ super.tearDown();
+ }
+}
diff --git a/tests/tests/media/src/android/media/cts/VirtualizerTest.java b/tests/tests/media/src/android/media/cts/VirtualizerTest.java
new file mode 100644
index 0000000..0a82f09
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/VirtualizerTest.java
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) 2010 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.media.cts;
+
+import android.media.audiofx.AudioEffect;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.audiofx.Virtualizer;
+import android.os.Looper;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+
+@TestTargetClass(Virtualizer.class)
+public class VirtualizerTest extends AndroidTestCase {
+
+ private String TAG = "VirtualizerTest";
+ private final static short TEST_STRENGTH = 500;
+ private final static short TEST_STRENGTH2 = 1000;
+ private final static float STRENGTH_TOLERANCE = 1.1f; // 10%
+
+ private Virtualizer mVirtualizer = null;
+ private Virtualizer mVirtualizer2 = null;
+ private int mSession = -1;
+ private boolean mHasControl = false;
+ private boolean mIsEnabled = false;
+ private int mChangedParameter = -1;
+ private boolean mInitialized = false;
+ private Looper mLooper = null;
+ private final Object mLock = new Object();
+
+ //-----------------------------------------------------------------
+ // VIRTUALIZER TESTS:
+ //----------------------------------
+
+ //-----------------------------------------------------------------
+ // 0 - constructor
+ //----------------------------------
+
+ //Test case 0.0: test constructor and release
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "Virtualizer",
+ args = {int.class, int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getId",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "release",
+ args = {}
+ )
+ })
+ public void test0_0ConstructorAndRelease() throws Exception {
+ Virtualizer eq = null;
+ try {
+ eq = new Virtualizer(0, 0);
+ assertNotNull(" could not create Virtualizer", eq);
+ try {
+ assertTrue(" invalid effect ID", (eq.getId() != 0));
+ } catch (IllegalStateException e) {
+ fail("Virtualizer not initialized");
+ }
+ } catch (IllegalArgumentException e) {
+ fail("Virtualizer not found");
+ } catch (UnsupportedOperationException e) {
+ fail("Effect library not loaded");
+ } finally {
+ if (eq != null) {
+ eq.release();
+ }
+ }
+ }
+
+
+ //-----------------------------------------------------------------
+ // 1 - get/set parameters
+ //----------------------------------
+
+ //Test case 1.0: test strength
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getStrengthSupported",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setStrength",
+ args = {short.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getRoundedStrength",
+ args = {}
+ )
+ })
+ public void test1_0Strength() throws Exception {
+ getVirtualizer(0);
+ try {
+ if (mVirtualizer.getStrengthSupported()) {
+ short strength = mVirtualizer.getRoundedStrength();
+ strength = (strength == TEST_STRENGTH) ? TEST_STRENGTH2 : TEST_STRENGTH;
+ mVirtualizer.setStrength((short)strength);
+ short strength2 = mVirtualizer.getRoundedStrength();
+ // allow STRENGTH_TOLERANCE difference between set strength and rounded strength
+ assertTrue("got incorrect strength",
+ ((float)strength2 > (float)strength / STRENGTH_TOLERANCE) &&
+ ((float)strength2 < (float)strength * STRENGTH_TOLERANCE));
+ } else {
+ short strength = mVirtualizer.getRoundedStrength();
+ assertTrue("got incorrect strength", strength >= 0 && strength <= 1000);
+ }
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("get parameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("get parameter() called in wrong state");
+ } finally {
+ releaseVirtualizer();
+ }
+ }
+
+ //Test case 1.1: test properties
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getProperties",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setProperties",
+ args = {Virtualizer.Settings.class}
+ )
+ })
+ public void test1_1Properties() throws Exception {
+ getVirtualizer(0);
+ try {
+ Virtualizer.Settings settings = mVirtualizer.getProperties();
+ String str = settings.toString();
+ settings = new Virtualizer.Settings(str);
+
+ short strength = settings.strength;
+ if (mVirtualizer.getStrengthSupported()) {
+ strength = (strength == TEST_STRENGTH) ? TEST_STRENGTH2 : TEST_STRENGTH;
+ }
+ settings.strength = strength;
+ mVirtualizer.setProperties(settings);
+ settings = mVirtualizer.getProperties();
+
+ if (mVirtualizer.getStrengthSupported()) {
+ // allow STRENGTH_TOLERANCE difference between set strength and rounded strength
+ assertTrue("got incorrect strength",
+ ((float)settings.strength > (float)strength / STRENGTH_TOLERANCE) &&
+ ((float)settings.strength < (float)strength * STRENGTH_TOLERANCE));
+ }
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("get parameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("get parameter() called in wrong state");
+ } finally {
+ releaseVirtualizer();
+ }
+ }
+
+ //Test case 1.2: test setStrength() throws exception after release
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "release",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setStrength",
+ args = {short.class}
+ )
+ })
+ public void test1_2SetStrengthAfterRelease() throws Exception {
+ getVirtualizer(0);
+ mVirtualizer.release();
+ try {
+ mVirtualizer.setStrength(TEST_STRENGTH);
+ } catch (IllegalStateException e) {
+ // test passed
+ } finally {
+ releaseVirtualizer();
+ }
+ }
+
+ //-----------------------------------------------------------------
+ // 2 - Effect enable/disable
+ //----------------------------------
+
+ //Test case 2.0: test setEnabled() and getEnabled() in valid state
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnabled",
+ args = {boolean.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getEnabled",
+ args = {}
+ )
+ })
+ public void test2_0SetEnabledGetEnabled() throws Exception {
+ getVirtualizer(0);
+ try {
+ mVirtualizer.setEnabled(true);
+ assertTrue(" invalid state from getEnabled", mVirtualizer.getEnabled());
+ mVirtualizer.setEnabled(false);
+ assertFalse(" invalid state to getEnabled", mVirtualizer.getEnabled());
+ } catch (IllegalStateException e) {
+ fail("setEnabled() in wrong state");
+ } finally {
+ releaseVirtualizer();
+ }
+ }
+
+ //Test case 2.1: test setEnabled() throws exception after release
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "release",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnabled",
+ args = {boolean.class}
+ )
+ })
+ public void test2_1SetEnabledAfterRelease() throws Exception {
+ getVirtualizer(0);
+ mVirtualizer.release();
+ try {
+ mVirtualizer.setEnabled(true);
+ } catch (IllegalStateException e) {
+ // test passed
+ } finally {
+ releaseVirtualizer();
+ }
+ }
+
+ //-----------------------------------------------------------------
+ // 3 priority and listeners
+ //----------------------------------
+
+ //Test case 3.0: test control status listener
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setControlStatusListener",
+ args = {AudioEffect.OnControlStatusChangeListener.class}
+ )
+ })
+ public void test3_0ControlStatusListener() throws Exception {
+ mHasControl = true;
+ createListenerLooper(true, false, false);
+ synchronized(mLock) {
+ try {
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Looper creation: wait was interrupted.");
+ }
+ }
+ assertTrue(mInitialized);
+ synchronized(mLock) {
+ try {
+ getVirtualizer(0);
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Create second effect: wait was interrupted.");
+ } finally {
+ releaseVirtualizer();
+ terminateListenerLooper();
+ }
+ }
+ assertFalse("effect control not lost by effect1", mHasControl);
+ }
+
+ //Test case 3.1: test enable status listener
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnableStatusListener",
+ args = {AudioEffect.OnEnableStatusChangeListener.class}
+ )
+ })
+ public void test3_1EnableStatusListener() throws Exception {
+ createListenerLooper(false, true, false);
+ synchronized(mLock) {
+ try {
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Looper creation: wait was interrupted.");
+ }
+ }
+ assertTrue(mInitialized);
+ mVirtualizer2.setEnabled(true);
+ mIsEnabled = true;
+ getVirtualizer(0);
+ synchronized(mLock) {
+ try {
+ mVirtualizer.setEnabled(false);
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Create second effect: wait was interrupted.");
+ } finally {
+ releaseVirtualizer();
+ terminateListenerLooper();
+ }
+ }
+ assertFalse("enable status not updated", mIsEnabled);
+ }
+
+ //Test case 3.2: test parameter changed listener
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setParameterListener",
+ args = {Virtualizer.OnParameterChangeListener.class}
+ )
+ })
+ public void test3_2ParameterChangedListener() throws Exception {
+ createListenerLooper(false, false, true);
+ synchronized(mLock) {
+ try {
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Looper creation: wait was interrupted.");
+ }
+ }
+ assertTrue(mInitialized);
+ getVirtualizer(0);
+ synchronized(mLock) {
+ try {
+ mChangedParameter = -1;
+ mVirtualizer.setStrength(TEST_STRENGTH);
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Create second effect: wait was interrupted.");
+ } finally {
+ releaseVirtualizer();
+ terminateListenerLooper();
+ }
+ }
+ assertEquals("parameter change not received",
+ Virtualizer.PARAM_STRENGTH, mChangedParameter);
+ }
+
+ //-----------------------------------------------------------------
+ // private methods
+ //----------------------------------
+
+ private void getVirtualizer(int session) {
+ if (mVirtualizer == null || session != mSession) {
+ if (session != mSession && mVirtualizer != null) {
+ mVirtualizer.release();
+ mVirtualizer = null;
+ }
+ try {
+ mVirtualizer = new Virtualizer(0, session);
+ mSession = session;
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "getVirtualizer() Virtualizer not found exception: "+e);
+ } catch (UnsupportedOperationException e) {
+ Log.e(TAG, "getVirtualizer() Effect library not loaded exception: "+e);
+ }
+ }
+ assertNotNull("could not create mVirtualizer", mVirtualizer);
+ }
+
+ private void releaseVirtualizer() {
+ if (mVirtualizer != null) {
+ mVirtualizer.release();
+ mVirtualizer = null;
+ }
+ }
+
+ // Initializes the virtualizer listener looper
+ class ListenerThread extends Thread {
+ boolean mControl;
+ boolean mEnable;
+ boolean mParameter;
+
+ public ListenerThread(boolean control, boolean enable, boolean parameter) {
+ super();
+ mControl = control;
+ mEnable = enable;
+ mParameter = parameter;
+ }
+ }
+
+ private void createListenerLooper(boolean control, boolean enable, boolean parameter) {
+ mInitialized = false;
+ new ListenerThread(control, enable, parameter) {
+ @Override
+ public void run() {
+ // Set up a looper
+ Looper.prepare();
+
+ // Save the looper so that we can terminate this thread
+ // after we are done with it.
+ mLooper = Looper.myLooper();
+
+ mVirtualizer2 = new Virtualizer(0, 0);
+ assertNotNull("could not create virtualizer2", mVirtualizer2);
+
+ if (mControl) {
+ mVirtualizer2.setControlStatusListener(
+ new AudioEffect.OnControlStatusChangeListener() {
+ public void onControlStatusChange(
+ AudioEffect effect, boolean controlGranted) {
+ synchronized(mLock) {
+ if (effect == mVirtualizer2) {
+ mHasControl = controlGranted;
+ mLock.notify();
+ }
+ }
+ }
+ });
+ }
+ if (mEnable) {
+ mVirtualizer2.setEnableStatusListener(
+ new AudioEffect.OnEnableStatusChangeListener() {
+ public void onEnableStatusChange(AudioEffect effect, boolean enabled) {
+ synchronized(mLock) {
+ if (effect == mVirtualizer2) {
+ mIsEnabled = enabled;
+ mLock.notify();
+ }
+ }
+ }
+ });
+ }
+ if (mParameter) {
+ mVirtualizer2.setParameterListener(new Virtualizer.OnParameterChangeListener() {
+ public void onParameterChange(Virtualizer effect, int status,
+ int param, short value)
+ {
+ synchronized(mLock) {
+ if (effect == mVirtualizer2) {
+ mChangedParameter = param;
+ mLock.notify();
+ }
+ }
+ }
+ });
+ }
+
+ synchronized(mLock) {
+ mInitialized = true;
+ mLock.notify();
+ }
+ Looper.loop(); // Blocks forever until Looper.quit() is called.
+ }
+ }.start();
+ }
+
+ // Terminates the listener looper thread.
+ private void terminateListenerLooper() {
+ if (mVirtualizer2 != null) {
+ mVirtualizer2.release();
+ mVirtualizer2 = null;
+ }
+ if (mLooper != null) {
+ mLooper.quit();
+ mLooper = null;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/tests/tests/media/src/android/media/cts/VisualizerTest.java b/tests/tests/media/src/android/media/cts/VisualizerTest.java
new file mode 100644
index 0000000..6b29948
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/VisualizerTest.java
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2010 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.media.cts;
+
+import android.media.audiofx.AudioEffect;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.audiofx.Visualizer;
+import android.os.Looper;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+
+@TestTargetClass(Visualizer.class)
+public class VisualizerTest extends AndroidTestCase {
+
+ private String TAG = "VisualizerTest";
+ private final static int MIN_CAPTURE_RATE_MAX = 10000; // 10Hz
+ private final static int MIN_CAPTURE_SIZE_MAX = 1024;
+ private final static int MAX_CAPTURE_SIZE_MIN = 512;
+
+ private Visualizer mVisualizer = null;
+ private int mSession = -1;
+ private boolean mInitialized = false;
+ private Looper mLooper = null;
+ private final Object mLock = new Object();
+ private byte[] mWaveform = null;
+ private byte[] mFft = null;
+ private boolean mCaptureWaveform = false;
+ private boolean mCaptureFft = false;
+
+ //-----------------------------------------------------------------
+ // VISUALIZER TESTS:
+ //----------------------------------
+
+ //-----------------------------------------------------------------
+ // 0 - constructor
+ //----------------------------------
+
+ //Test case 0.0: test constructor and release
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "Visualizer",
+ args = {int.class, int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "release",
+ args = {}
+ )
+ })
+ public void test0_0ConstructorAndRelease() throws Exception {
+ Visualizer visualizer = null;
+ try {
+ visualizer = new Visualizer(0);
+ assertNotNull("could not create Visualizer", visualizer);
+ } catch (IllegalArgumentException e) {
+ fail("Visualizer not found");
+ } catch (UnsupportedOperationException e) {
+ fail("Effect library not loaded");
+ } finally {
+ if (visualizer != null) {
+ visualizer.release();
+ }
+ }
+ }
+
+
+ //-----------------------------------------------------------------
+ // 1 - get/set parameters
+ //----------------------------------
+
+ //Test case 1.0: capture rates
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getMaxCaptureRate",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getSamplingRate",
+ args = {}
+ )
+ })
+ public void test1_0CaptureRates() throws Exception {
+ getVisualizer(0);
+ try {
+ int captureRate = mVisualizer.getMaxCaptureRate();
+ assertTrue("insufficient max capture rate",
+ captureRate >= MIN_CAPTURE_RATE_MAX);
+ int samplingRate = mVisualizer.getSamplingRate();
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("get parameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("get parameter() called in wrong state");
+ } finally {
+ releaseVisualizer();
+ }
+ }
+
+ //Test case 1.1: test capture size
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getCaptureSizeRange",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setCaptureSize",
+ args = {int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getCaptureSize",
+ args = {}
+ )
+ })
+ public void test1_1CaptureSize() throws Exception {
+ getVisualizer(0);
+ try {
+ int[] range = mVisualizer.getCaptureSizeRange();
+ assertTrue("insufficient min capture size",
+ range[0] <= MAX_CAPTURE_SIZE_MIN);
+ assertTrue("insufficient min capture size",
+ range[1] >= MIN_CAPTURE_SIZE_MAX);
+ mVisualizer.setCaptureSize(range[0]);
+ assertEquals("insufficient min capture size",
+ range[0], mVisualizer.getCaptureSize());
+ mVisualizer.setCaptureSize(range[1]);
+ assertEquals("insufficient min capture size",
+ range[1], mVisualizer.getCaptureSize());
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("get parameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("get parameter() called in wrong state");
+ } finally {
+ releaseVisualizer();
+ }
+ }
+
+ //-----------------------------------------------------------------
+ // 2 - check capture
+ //----------------------------------
+
+ //Test case 2.0: test cature in polling mode
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnabled",
+ args = {boolean.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getEnabled",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getWaveForm",
+ args = {byte[].class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getFft",
+ args = {byte[].class}
+ )
+ })
+ public void test2_0PollingCapture() throws Exception {
+ try {
+ getVisualizer(0);
+ mVisualizer.setEnabled(true);
+ assertTrue("visualizer not enabled", mVisualizer.getEnabled());
+ Thread.sleep(100);
+ // check capture on silence
+ byte[] data = new byte[mVisualizer.getCaptureSize()];
+ mVisualizer.getWaveForm(data);
+ int energy = computeEnergy(data, true);
+ assertEquals("getWaveForm reports energy for silence",
+ 0, energy);
+ mVisualizer.getFft(data);
+ energy = computeEnergy(data, false);
+ assertEquals("getFft reports energy for silence",
+ 0, energy);
+
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("get parameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("get parameter() called in wrong state");
+ } catch (InterruptedException e) {
+ fail("sleep() interrupted");
+ }
+ finally {
+ releaseVisualizer();
+ }
+ }
+
+ //Test case 2.1: test capture with listener
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setEnabled",
+ args = {boolean.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getEnabled",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setDataCaptureListener",
+ args = {Visualizer.OnDataCaptureListener.class,
+ int.class, boolean.class, boolean.class}
+ )
+ })
+ public void test2_1ListenerCapture() throws Exception {
+ try {
+ getVisualizer(0);
+ createListenerLooper();
+ synchronized(mLock) {
+ try {
+ mLock.wait(1000);
+ } catch(Exception e) {
+ Log.e(TAG, "Looper creation: wait was interrupted.");
+ }
+ }
+ assertTrue(mInitialized);
+
+ mVisualizer.setEnabled(true);
+ assertTrue("visualizer not enabled", mVisualizer.getEnabled());
+
+ Thread.sleep(100);
+ // check capture on silence
+ synchronized(mLock) {
+ try {
+ mCaptureWaveform = true;
+ mLock.wait(1000);
+ mCaptureWaveform = false;
+ } catch(Exception e) {
+ Log.e(TAG, "Capture waveform: wait was interrupted.");
+ }
+ }
+ assertNotNull("waveform capture failed", mWaveform);
+ int energy = computeEnergy(mWaveform, true);
+ assertEquals("getWaveForm reports energy for silence",
+ 0, energy);
+
+ synchronized(mLock) {
+ try {
+ mCaptureFft = true;
+ mLock.wait(1000);
+ mCaptureFft = false;
+ } catch(Exception e) {
+ Log.e(TAG, "Capture FFT: wait was interrupted.");
+ }
+ }
+ assertNotNull("FFT capture failed", mFft);
+ energy = computeEnergy(mFft, false);
+ assertEquals("getFft reports energy for silence",
+ 0, energy);
+
+ } catch (IllegalArgumentException e) {
+ fail("Bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("get parameter() rejected");
+ } catch (IllegalStateException e) {
+ fail("get parameter() called in wrong state");
+ } catch (InterruptedException e) {
+ fail("sleep() interrupted");
+ } finally {
+ terminateListenerLooper();
+ releaseVisualizer();
+ }
+ }
+
+ //-----------------------------------------------------------------
+ // private methods
+ //----------------------------------
+
+ private int computeEnergy(byte[] data, boolean pcm) {
+ int energy = 0;
+ if (data.length != 0) {
+ if (pcm) {
+ for (int i = 0; i < data.length; i++) {
+ int tmp = ((int)data[i] & 0xFF) - 128;
+ energy += tmp*tmp;
+ }
+ } else {
+ energy = (int)data[0] * (int)data[0];
+ for (int i = 2; i < data.length; i += 2) {
+ int real = (int)data[i];
+ int img = (int)data[i + 1];
+ energy += real * real + img * img;
+ }
+ }
+ }
+ return energy;
+ }
+
+ private void getVisualizer(int session) {
+ if (mVisualizer == null || session != mSession) {
+ if (session != mSession && mVisualizer != null) {
+ mVisualizer.release();
+ mVisualizer = null;
+ }
+ try {
+ mVisualizer = new Visualizer(session);
+ mSession = session;
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "getVisualizer() Visualizer not found exception: "+e);
+ } catch (UnsupportedOperationException e) {
+ Log.e(TAG, "getVisualizer() Effect library not loaded exception: "+e);
+ }
+ }
+ assertNotNull("could not create mVisualizer", mVisualizer);
+ }
+
+ private void releaseVisualizer() {
+ if (mVisualizer != null) {
+ mVisualizer.release();
+ mVisualizer = null;
+ }
+ }
+
+ private void createListenerLooper() {
+
+ new Thread() {
+ @Override
+ public void run() {
+ // Set up a looper to be used by mEffect.
+ Looper.prepare();
+
+ // Save the looper so that we can terminate this thread
+ // after we are done with it.
+ mLooper = Looper.myLooper();
+
+ if (mVisualizer != null) {
+ mVisualizer.setDataCaptureListener(new Visualizer.OnDataCaptureListener() {
+ public void onWaveFormDataCapture(
+ Visualizer visualizer, byte[] waveform, int samplingRate) {
+ synchronized(mLock) {
+ if (visualizer == mVisualizer) {
+ if (mCaptureWaveform) {
+ mWaveform = waveform;
+ mLock.notify();
+ }
+ }
+ }
+ }
+
+ public void onFftDataCapture(
+ Visualizer visualizer, byte[] fft, int samplingRate) {
+ synchronized(mLock) {
+ if (visualizer == mVisualizer) {
+ if (mCaptureFft) {
+ mFft = fft;
+ mLock.notify();
+ }
+ }
+ }
+ }
+ },
+ 10000,
+ true,
+ true);
+ }
+
+ synchronized(mLock) {
+ mInitialized = true;
+ mLock.notify();
+ }
+ Looper.loop(); // Blocks forever until Looper.quit() is called.
+ }
+ }.start();
+ }
+ /*
+ * Terminates the listener looper thread.
+ */
+ private void terminateListenerLooper() {
+ if (mLooper != null) {
+ mLooper.quit();
+ mLooper = null;
+ }
+ }
+}
diff --git a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
index edcea9a2..cfe0872 100644
--- a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -97,67 +97,6 @@
assertFalse(ConnectivityManager.isNetworkTypeValid(-1));
}
- @TestTargets({
- @TestTargetNew(
- level = TestLevel.COMPLETE,
- method = "getNetworkPreference",
- args = {}
- ),
- @TestTargetNew(
- level = TestLevel.SUFFICIENT,
- method = "setNetworkPreference",
- args = {int.class}
- )
- })
- public void testAccessNetworkPreference() {
- int initialSetting = mCm.getNetworkPreference();
-
- // Changing the network preference requires android.permission.WRITE_SECURE_SETTINGS,
- // which is only available to signed or system applications.
-
- // Setting the same preference that is already set is a no-op and does not throw
- // a SecurityException.
- mCm.setNetworkPreference(initialSetting);
- assertEquals(initialSetting, mCm.getNetworkPreference());
-
- // find a valid setting that is different from the initial setting
- int validSetting = -1;
- NetworkInfo[] ni = mCm.getAllNetworkInfo();
- for (NetworkInfo n : ni) {
- int type = n.getType();
- if (type != initialSetting) {
- validSetting = type;
- break;
- }
- }
- if (validSetting >= 0) {
- try {
- mCm.setNetworkPreference(validSetting);
- fail("Trying to change the network preference should throw SecurityException");
- } catch (SecurityException expected) {
- // expected
- }
- }
-
- // find an invalid setting
- int invalidSetting = -1;
- for (int i = 0; i < 10; i++) {
- if (!ConnectivityManager.isNetworkTypeValid(i)) {
- invalidSetting = i;
- break;
- }
- }
- if (invalidSetting >= 0) {
- // illegal setting should be ignored
- mCm.setNetworkPreference(invalidSetting);
- assertEquals(initialSetting, mCm.getNetworkPreference());
- }
-
- // illegal setting should be ignored
- mCm.setNetworkPreference(-1);
- assertEquals(initialSetting, mCm.getNetworkPreference());
- }
-
@TestTargetNew(
level = TestLevel.COMPLETE,
notes = "Test getAllNetworkInfo().",
diff --git a/tests/tests/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/tests/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java
index 6cd5d6f..258ac4d 100644
--- a/tests/tests/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java
+++ b/tests/tests/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java
@@ -21,6 +21,7 @@
import java.net.Socket;
import javax.net.SocketFactory;
+import javax.net.ssl.SSLPeerUnverifiedException;
import android.net.SSLCertificateSocketFactory;
import android.test.AndroidTestCase;
@@ -141,4 +142,73 @@
// The socket level is invalid.
}
+ // a host and port that are expected to be available but have
+ // a cert with a different CN, in this case CN=mtalk.google.com
+ private static String TEST_CREATE_SOCKET_HOST = "mobile-gtalk.l.google.com";
+ private static int TEST_CREATE_SOCKET_PORT = 5228;
+
+ /**
+ * b/2807618 Make sure that hostname verifcation in cases were it
+ * is documented to be included by various
+ * SSLCertificateSocketFactory.createSocket messages.
+ *
+ * NOTE: Test will fail if external server is not available.
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "createSocket",
+ args = {String.class, int.class}
+ )
+ public void test_createSocket_simple() throws Exception {
+ try {
+ mFactory.createSocket(TEST_CREATE_SOCKET_HOST, TEST_CREATE_SOCKET_PORT);
+ fail();
+ } catch (SSLPeerUnverifiedException expected) {
+ // expected
+ }
+ }
+
+ /**
+ * b/2807618 Make sure that hostname verifcation in cases were it
+ * is documented to be included by various
+ * SSLCertificateSocketFactory.createSocket messages.
+ *
+ * NOTE: Test will fail if external server is not available.
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "createSocket",
+ args = {Socket.class, String.class, int.class, boolean.class}
+ )
+ public void test_createSocket_wrapping() throws Exception {
+ try {
+ Socket underlying = new Socket(TEST_CREATE_SOCKET_HOST, TEST_CREATE_SOCKET_PORT);
+ mFactory.createSocket(
+ underlying, TEST_CREATE_SOCKET_HOST, TEST_CREATE_SOCKET_PORT, true);
+ fail();
+ } catch (SSLPeerUnverifiedException expected) {
+ // expected
+ }
+ }
+
+ /**
+ * b/2807618 Make sure that hostname verifcation in cases were it
+ * is documented to be included by various
+ * SSLCertificateSocketFactory.createSocket messages.
+ *
+ * NOTE: Test will fail if external server is not available.
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "createSocket",
+ args = {String.class, int.class, InetAddress.class, int.class}
+ )
+ public void test_createSocket_bind() throws Exception {
+ try {
+ mFactory.createSocket(TEST_CREATE_SOCKET_HOST, TEST_CREATE_SOCKET_PORT, null, 0);
+ fail();
+ } catch (SSLPeerUnverifiedException expected) {
+ // expected
+ }
+ }
}
diff --git a/tests/tests/os/src/android/os/cts/BuildTest.java b/tests/tests/os/src/android/os/cts/BuildTest.java
index 62abc5a..a0b0459 100644
--- a/tests/tests/os/src/android/os/cts/BuildTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildTest.java
@@ -108,9 +108,12 @@
private static final Pattern DEVICE_PATTERN =
Pattern.compile("^([0-9A-Za-z_-]+)$");
+ private static final Pattern SERIAL_NUMBER_PATTERN =
+ Pattern.compile("^([0-9A-Za-z]{0,20})$");
/** Tests that check for valid values of constants in Build. */
public void testBuildConstants() {
+ assertTrue(SERIAL_NUMBER_PATTERN.matcher(Build.SERIAL).matches());
assertTrue(DEVICE_PATTERN.matcher(Build.DEVICE).matches());
}
}
diff --git a/tests/tests/os/src/android/os/cts/BuildVersionTest.java b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
index 61e1837..7225363 100644
--- a/tests/tests/os/src/android/os/cts/BuildVersionTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
@@ -27,20 +27,21 @@
public class BuildVersionTest extends TestCase {
private static final String LOG_TAG = "BuildVersionTest";
- private static final String EXPECTED_RELEASE = "2.2.1";
- private static final String EXPECTED_SDK = "8";
+ private static final String EXPECTED_RELEASE = "2.3";
+ private static final int EXPECTED_SDK = 9;
public void testReleaseVersion() {
// Applications may rely on the exact release version
assertEquals(EXPECTED_RELEASE, Build.VERSION.RELEASE);
- assertEquals(EXPECTED_SDK, Build.VERSION.SDK);
+ assertEquals("" + EXPECTED_SDK, Build.VERSION.SDK);
+ assertEquals(EXPECTED_SDK, Build.VERSION.SDK_INT);
}
/**
* Verifies {@link Build.FINGERPRINT} follows expected format:
* <p/>
* <code>
- * (BRAND)/(PRODUCT)/(DEVICE)/(BOARD):(VERSION.RELEASE)/(BUILD_ID)/
+ * (BRAND)/(PRODUCT)/(DEVICE):(VERSION.RELEASE)/(BUILD_ID)/
* (BUILD_NUMBER):(BUILD_VARIANT)/(TAGS)
* </code>
*/
@@ -51,18 +52,19 @@
assertEquals("Build fingerprint must not include whitespace", -1,
fingerprint.indexOf(' '));
final String[] fingerprintSegs = fingerprint.split("/");
- assertEquals("Build fingerprint does not match expected format", 7, fingerprintSegs.length);
+ assertEquals("Build fingerprint does not match expected format", 6, fingerprintSegs.length);
assertEquals(Build.BRAND, fingerprintSegs[0]);
assertEquals(Build.PRODUCT, fingerprintSegs[1]);
- assertEquals(Build.DEVICE, fingerprintSegs[2]);
- // parse BOARD:VERSION_RELEASE
- String[] bootloaderPlat = fingerprintSegs[3].split(":");
- assertEquals(Build.BOARD, bootloaderPlat[0]);
- assertEquals(Build.VERSION.RELEASE, bootloaderPlat[1]);
- assertEquals(Build.ID, fingerprintSegs[4]);
+
+ String[] devicePlatform = fingerprintSegs[2].split(":");
+ assertEquals(2, devicePlatform.length);
+ assertEquals(Build.DEVICE, devicePlatform[0]);
+ assertEquals(Build.VERSION.RELEASE, devicePlatform[1]);
+
+ assertEquals(Build.ID, fingerprintSegs[3]);
// no requirements for BUILD_NUMBER and BUILD_VARIANT
- assertTrue(fingerprintSegs[5].contains(":"));
+ assertTrue(fingerprintSegs[4].contains(":"));
// no strict requirement for TAGS
- //assertEquals(Build.TAGS, fingerprintSegs[6]);
+ //assertEquals(Build.TAGS, fingerprintSegs[5]);
}
}
diff --git a/tests/tests/permission/src/android/permission/cts/DevicePowerPermissionTest.java b/tests/tests/permission/src/android/permission/cts/DevicePowerPermissionTest.java
index 3fccfaf..c5f8ea5 100644
--- a/tests/tests/permission/src/android/permission/cts/DevicePowerPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/DevicePowerPermissionTest.java
@@ -48,21 +48,4 @@
// expected
}
}
-
- /**
- * Verify that generating user activity requires Permission.
- * <p>Requires Permission:
- * {@link android.Manifest.permission#DEVICE_POWER}.
- *
- * TODO: add back SmallTest annotation when test has been fixed
- */
- @KnownFailure("will be fixed in future release")
- public void testUserActivity() {
- try {
- mPowerManager.userActivity(0, false);
- fail("Was able to call PowerManager.userActivity without DEVICE_POWER Permission.");
- } catch (SecurityException e) {
- // expected
- }
- }
}
diff --git a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
new file mode 100644
index 0000000..a5920fc
--- /dev/null
+++ b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2010 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.permission.cts;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Environment;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Verify certain permissions on the filesystem
+ */
+@MediumTest
+public class FileSystemPermissionTest extends AndroidTestCase {
+
+ public void testCreateFileHasSanePermissions() throws Exception {
+ File myFile = new File(getContext().getFilesDir(), "hello");
+ FileOutputStream stream = new FileOutputStream(myFile);
+ stream.write("hello world".getBytes());
+ stream.close();
+ try {
+ FileUtils.FileStatus status = new FileUtils.FileStatus();
+ FileUtils.getFileStatus(myFile.getAbsolutePath(), status, false);
+ int expectedPerms = FileUtils.S_IFREG
+ | FileUtils.S_IWUSR
+ | FileUtils.S_IRUSR;
+ assertEquals(
+ "Newly created files should have 0600 permissions",
+ Integer.toOctalString(expectedPerms),
+ Integer.toOctalString(status.mode));
+ } finally {
+ assertTrue(myFile.delete());
+ }
+ }
+
+ public void testCreateDirectoryHasSanePermissions() throws Exception {
+ File myDir = new File(getContext().getFilesDir(), "helloDirectory");
+ assertTrue(myDir.mkdir());
+ try {
+ FileUtils.FileStatus status = new FileUtils.FileStatus();
+ FileUtils.getFileStatus(myDir.getAbsolutePath(), status, false);
+ int expectedPerms = FileUtils.S_IFDIR
+ | FileUtils.S_IWUSR
+ | FileUtils.S_IRUSR
+ | FileUtils.S_IXUSR;
+ assertEquals(
+ "Newly created directories should have 0700 permissions",
+ Integer.toOctalString(expectedPerms),
+ Integer.toOctalString(status.mode));
+
+ } finally {
+ assertTrue(myDir.delete());
+ }
+ }
+
+ public void testOtherApplicationDirectoriesAreNotWritable() throws Exception {
+ List<ApplicationInfo> apps = getContext()
+ .getPackageManager()
+ .getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);
+ String myAppDirectory = getContext().getApplicationInfo().dataDir;
+ for (ApplicationInfo app : apps) {
+ if (!myAppDirectory.equals(app.dataDir)) {
+ assertDirectoryAndSubdirectoriesNotWritable(new File(app.dataDir));
+ }
+ }
+ }
+
+ public void testApplicationParentDirectoryNotWritable() throws Exception {
+ String myDataDir = getContext().getApplicationInfo().dataDir;
+ File parentDir = new File(myDataDir).getParentFile();
+ assertDirectoryNotWritable(parentDir);
+ }
+
+ public void testDataDirectoryNotWritable() throws Exception {
+ assertDirectoryNotWritable(Environment.getDataDirectory());
+ }
+
+ public void testAndroidRootDirectoryNotWritable() throws Exception {
+ assertDirectoryNotWritable(Environment.getRootDirectory());
+ }
+
+ public void testDownloadCacheDirectoryNotWritable() throws Exception {
+ assertDirectoryNotWritable(Environment.getDownloadCacheDirectory());
+ }
+
+ public void testRootDirectoryNotWritable() throws Exception {
+ assertDirectoryNotWritable(new File("/"));
+ }
+
+ public void testDevDirectoryNotWritable() throws Exception {
+ assertDirectoryNotWritable(new File("/dev"));
+ }
+
+ public void testProcDirectoryNotWritable() throws Exception {
+ assertDirectoryNotWritable(new File("/proc"));
+ }
+
+ private static void assertDirectoryNotWritable(File directory) throws Exception {
+ File toCreate = new File(directory, "hello");
+ try {
+ toCreate.createNewFile();
+ fail("Expected \"java.io.IOException: Permission denied\""
+ + " when trying to create " + toCreate.getAbsolutePath());
+ } catch (IOException e) {
+ // It's expected we'll get a "Permission denied" exception.
+ } finally {
+ toCreate.delete();
+ }
+ }
+
+ /**
+ * Verify that any publicly readable directories reachable from
+ * the root directory are not writable.
+ *
+ * Note: Because not all directories are readable, this is a best-effort
+ * test only. Writable directories within unreadable subdirectories
+ * will NOT be detected by this code.
+ */
+ public void testAllOtherDirectoriesNotWritable() throws Exception {
+ File start = new File("/");
+ assertDirectoryAndSubdirectoriesNotWritable(start);
+ }
+
+ private void assertDirectoryAndSubdirectoriesNotWritable(File dir) throws Exception {
+ if (!dir.isDirectory()) {
+ return;
+ }
+
+ if (!dir.getAbsolutePath().equals(dir.getCanonicalPath())) {
+ // don't follow symbolic links.
+ return;
+ }
+
+ String myHome = getContext().getApplicationInfo().dataDir;
+ String thisDir = dir.getCanonicalPath();
+ if (thisDir.startsWith(myHome)) {
+ // Don't examine directories within our home directory.
+ // We expect these directories to be writable.
+ return;
+ }
+
+ assertDirectoryNotWritable(dir);
+
+ File[] subFiles = dir.listFiles();
+ if (subFiles == null) {
+ return;
+ }
+
+ for (File f : subFiles) {
+ assertDirectoryAndSubdirectoriesNotWritable(f);
+ }
+ }
+}
diff --git a/tests/tests/permission/src/android/permission/cts/NoActivityRelatedPermissionTest.java b/tests/tests/permission/src/android/permission/cts/NoActivityRelatedPermissionTest.java
index 39da4b6..c73d31a 100644
--- a/tests/tests/permission/src/android/permission/cts/NoActivityRelatedPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/NoActivityRelatedPermissionTest.java
@@ -91,22 +91,6 @@
}
/**
- * Verify that setting Activity's persistent attribute requires permissions.
- * <p>Requires Permission:
- * {@link android.Manifest.permission#PERSISTENT_ACTIVITY}.
- */
- @UiThreadTest
- @MediumTest
- public void testSetPersistent() {
- try {
- mActivity.setPersistent(true);
- fail("Activity.setPersistent() did not throw SecurityException as expected");
- } catch (SecurityException e) {
- // Expected
- }
- }
-
- /**
* Verify that get task requires permissions.
* <p>Requires Permission:
* {@link android.Manifest.permission#GET_TASKS}
diff --git a/tests/tests/provider/src/android/provider/cts/SettingsTest.java b/tests/tests/provider/src/android/provider/cts/SettingsTest.java
index e3ca242..73fd836 100644
--- a/tests/tests/provider/src/android/provider/cts/SettingsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/SettingsTest.java
@@ -28,10 +28,10 @@
import android.os.RemoteException;
import android.provider.Settings;
import android.test.AndroidTestCase;
+import android.util.Log;
@TestTargetClass(android.provider.Settings.class)
public class SettingsTest extends AndroidTestCase {
-
public void testSystemTable() throws RemoteException {
final String[] SYSTEM_PROJECTION = new String[] {
Settings.System._ID, Settings.System.NAME, Settings.System.VALUE
diff --git a/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java
index 3f75f94..a97aa96 100644
--- a/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java
@@ -17,12 +17,15 @@
package android.telephony.cts;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.os.SystemClock;
import android.telephony.TelephonyManager;
import android.telephony.SmsManager;
import android.test.AndroidTestCase;
@@ -50,6 +53,12 @@
private static final String SMS_SEND_ACTION = "CTS_SMS_SEND_ACTION";
private static final String SMS_DELIVERY_ACTION = "CTS_SMS_DELIVERY_ACTION";
+ // List of network operators that don't support SMS delivery report
+ private static final List<String> NO_DELIVERY_REPORTS =
+ Arrays.asList(
+ "310410" // AT&T Mobility
+ );
+
private TelephonyManager mTelephonyManager;
private String mDestAddr;
private String mText;
@@ -59,6 +68,7 @@
private PendingIntent mDeliveredIntent;
private Intent mSendIntent;
private Intent mDeliveryIntent;
+ private boolean mDeliveryReportSupported;
private static final int TIME_OUT = 1000 * 60 * 4;
@@ -69,6 +79,18 @@
(TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
mDestAddr = mTelephonyManager.getLine1Number();
mText = "This is a test message";
+
+ if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
+ // CDMA supports SMS delivery report
+ mDeliveryReportSupported = true;
+ } else if (mTelephonyManager.getDeviceId().equals("000000000000000")) {
+ // emulator doesn't support SMS delivery report
+ mDeliveryReportSupported = false;
+ } else {
+ // is this a GSM network that doesn't support SMS delivery report?
+ String mccmnc = mTelephonyManager.getSimOperator();
+ mDeliveryReportSupported = !(NO_DELIVERY_REPORTS.contains(mccmnc));
+ }
}
@TestTargetNew(
@@ -120,8 +142,10 @@
// send single text sms
init();
sendTextMessage(mDestAddr, mDestAddr, mSentIntent, mDeliveredIntent);
- mSendReceiver.waitForCalls(1, TIME_OUT);
- mDeliveryReceiver.waitForCalls(1, TIME_OUT);
+ assertTrue(mSendReceiver.waitForCalls(1, TIME_OUT));
+ if (mDeliveryReportSupported) {
+ assertTrue(mDeliveryReceiver.waitForCalls(1, TIME_OUT));
+ }
if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
// TODO: temp workaround, OCTET encoding for EMS not properly supported
@@ -134,8 +158,10 @@
init();
sendDataMessage(mDestAddr, port, data, mSentIntent, mDeliveredIntent);
- mSendReceiver.waitForCalls(1, TIME_OUT);
- mDeliveryReceiver.waitForCalls(1, TIME_OUT);
+ assertTrue(mSendReceiver.waitForCalls(1, TIME_OUT));
+ if (mDeliveryReportSupported) {
+ assertTrue(mDeliveryReceiver.waitForCalls(1, TIME_OUT));
+ }
// send multi parts text sms
init();
@@ -148,8 +174,10 @@
deliveryIntents.add(PendingIntent.getBroadcast(getContext(), 0, mDeliveryIntent, 0));
}
sendMultiPartTextMessage(mDestAddr, parts, sentIntents, deliveryIntents);
- mSendReceiver.waitForCalls(numParts, TIME_OUT);
- mDeliveryReceiver.waitForCalls(numParts, TIME_OUT);
+ assertTrue(mSendReceiver.waitForCalls(numParts, TIME_OUT));
+ if (mDeliveryReportSupported) {
+ assertTrue(mDeliveryReceiver.waitForCalls(numParts, TIME_OUT));
+ }
}
private void init() {
@@ -220,12 +248,20 @@
}
}
- public void waitForCalls(int expectedCalls, long timeout) throws InterruptedException {
+ public boolean waitForCalls(int expectedCalls, long timeout) throws InterruptedException {
synchronized(mLock) {
mExpectedCalls = expectedCalls;
- if (mCalls < mExpectedCalls) {
- mLock.wait(timeout);
+ long startTime = SystemClock.elapsedRealtime();
+
+ while (mCalls < mExpectedCalls) {
+ long waitTime = timeout - (SystemClock.elapsedRealtime() - startTime);
+ if (waitTime > 0) {
+ mLock.wait(waitTime);
+ } else {
+ return false; // timed out
+ }
}
+ return true; // success
}
}
}
diff --git a/tests/tests/telephony/src/android/telephony/cts/SmsMessageTest.java b/tests/tests/telephony/src/android/telephony/cts/SmsMessageTest.java
index 44b0871..515f8b5 100644
--- a/tests/tests/telephony/src/android/telephony/cts/SmsMessageTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/SmsMessageTest.java
@@ -212,7 +212,7 @@
assertEquals(SCA2, sms.getServiceCenterAddress());
assertEquals(OA2, sms.getOriginatingAddress());
assertEquals(MESSAGE_BODY2, sms.getMessageBody());
- CharSequence msgBody = (CharSequence) sms.getMessageBody();
+ CharSequence msgBody = sms.getMessageBody();
result = SmsMessage.calculateLength(msgBody, false);
assertEquals(SMS_NUMBER2, result[0]);
assertEquals(sms.getMessageBody().length(), result[1]);
diff --git a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
index 6c13007..ae3d940 100644
--- a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
@@ -21,13 +21,12 @@
import dalvik.annotation.TestTargetNew;
import dalvik.annotation.TestTargets;
-import android.content.ContentResolver;
import android.content.Context;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
+import android.os.Build;
import android.os.Looper;
import android.os.cts.TestThread;
-import android.provider.Settings;
import android.telephony.CellLocation;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
@@ -297,7 +296,7 @@
case TelephonyManager.PHONE_TYPE_NONE:
assertNull(deviceId);
- assertHardwareId();
+ assertSerialNumber();
assertMacAddressReported();
break;
@@ -401,15 +400,13 @@
}
}
- private void assertHardwareId() {
- ContentResolver resolver = mContext.getContentResolver();
- String hardwareId = Settings.Secure.getString(resolver, "hardware_id");
- assertNotNull("Non-telephony devices must define a Settings.Secure 'hardware_id' property.",
- hardwareId);
+ private void assertSerialNumber() {
+ assertNotNull("Non-telephony devices must have a Build.SERIAL number.",
+ Build.SERIAL);
assertTrue("Hardware id must be no longer than 20 characters.",
- hardwareId.length() <= 20);
+ Build.SERIAL.length() <= 20);
assertTrue("Hardware id must be alphanumeric.",
- Pattern.matches("[0-9A-Za-z]+", hardwareId));
+ Pattern.matches("[0-9A-Za-z]+", Build.SERIAL));
}
private void assertMacAddressReported() {
diff --git a/tests/tests/telephony/src/android/telephony/gsm/cts/SmsManagerTest.java b/tests/tests/telephony/src/android/telephony/gsm/cts/SmsManagerTest.java
index 8dc6936..512e89d 100644
--- a/tests/tests/telephony/src/android/telephony/gsm/cts/SmsManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/gsm/cts/SmsManagerTest.java
@@ -28,6 +28,7 @@
@TestTargetClass(SmsManager.class)
public class SmsManagerTest extends android.telephony.cts.SmsManagerTest {
+ @Override
@TestTargetNew(
level = TestLevel.COMPLETE,
method = "getDefault",
diff --git a/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java b/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
index a7c55a1..1d6c109 100644
--- a/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
@@ -143,23 +143,6 @@
assertSelection(-1);
runTestOnUiThread(new Runnable() {
public void run() {
- mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_DOWN);
- }
- });
- getInstrumentation().waitForIdleSync();
- assertSelection(END_OF_1ST_LINE);
-
- runTestOnUiThread(new Runnable() {
- public void run() {
- Selection.removeSelection(mEditable);
- mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_RIGHT);
- }
- });
- getInstrumentation().waitForIdleSync();
- assertSelection(END_OF_1ST_LINE);
-
- runTestOnUiThread(new Runnable() {
- public void run() {
Selection.removeSelection(mEditable);
mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_UP);
}
@@ -189,22 +172,6 @@
runTestOnUiThread(new Runnable() {
public void run() {
Selection.removeSelection(mEditable);
- mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_DOWN);
- }
- });
- assertSelection(END_OF_ALL_TEXT);
-
- runTestOnUiThread(new Runnable() {
- public void run() {
- Selection.removeSelection(mEditable);
- mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_RIGHT);
- }
- });
- assertSelection(END_OF_ALL_TEXT);
-
- runTestOnUiThread(new Runnable() {
- public void run() {
- Selection.removeSelection(mEditable);
mArrowKeyMovementMethod.onTakeFocus(mTextView, mEditable, View.FOCUS_UP);
}
});
diff --git a/tests/tests/util/src/android/util/cts/TimeUtilsTest.java b/tests/tests/util/src/android/util/cts/TimeUtilsTest.java
index 8a720ef..47e37a0 100644
--- a/tests/tests/util/src/android/util/cts/TimeUtilsTest.java
+++ b/tests/tests/util/src/android/util/cts/TimeUtilsTest.java
@@ -21,8 +21,6 @@
import dalvik.annotation.TestTargetNew;
import dalvik.annotation.TestTargets;
-import org.apache.harmony.luni.internal.util.ZoneInfoDB;
-
import android.util.TimeUtils;
import java.util.Calendar;
@@ -473,20 +471,6 @@
}
}
- @TestTargets({
- @TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "Test method: getTimeZoneDatabaseVersion",
- method = "getTimeZoneDatabaseVersion",
- args = {}
- )
- })
- public void testGetTimeZoneDatabaseVersion(){
- String version = TimeUtils.getTimeZoneDatabaseVersion();
- assertTrue(5 == version.length());
- assertEquals(ZoneInfoDB.getVersion(), version);
- }
-
private static TimeZone guessTimeZone(Calendar c, String country) {
return TimeUtils.getTimeZone(c.get(Calendar.ZONE_OFFSET) + c.get(Calendar.DST_OFFSET),
c.get(Calendar.DST_OFFSET) != 0,
diff --git a/tests/tests/view/src/android/view/cts/MotionEventTest.java b/tests/tests/view/src/android/view/cts/MotionEventTest.java
index beece1e..e4df594 100644
--- a/tests/tests/view/src/android/view/cts/MotionEventTest.java
+++ b/tests/tests/view/src/android/view/cts/MotionEventTest.java
@@ -488,5 +488,13 @@
assertEquals(1, mMotionEvent2.getHistorySize());
mMotionEvent2.recycle();
+
+ try {
+ mMotionEvent2.recycle();
+ fail("recycle() should throw an exception when the event has already been recycled.");
+ } catch (RuntimeException ex) {
+ }
+
+ mMotionEvent2 = null; // since it was recycled, don't try to recycle again in tear down
}
}
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index 77624e8..e07e105 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -558,25 +558,6 @@
assertEquals(-1, view.getBaseline());
}
- @TestTargetNew(
- level = TestLevel.COMPLETE,
- method = "computeScroll",
- args = {}
- )
- public void testComputeScroll() throws Throwable {
- final MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
- assertTrue(view.hasCalledComputeScroll());
-
- view.reset();
- runTestOnUiThread(new Runnable() {
- public void run() {
- view.requestLayout();
- }
- });
- getInstrumentation().waitForIdleSync();
- assertTrue(view.hasCalledComputeScroll());
- }
-
@TestTargets({
@TestTargetNew(
level = TestLevel.COMPLETE,
@@ -2723,8 +2704,7 @@
});
assertFalse(view.hasCalledOnKeyMultiple());
- KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_ENTER);
- getInstrumentation().sendKeySync(keyEvent);
+ view.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_ENTER));
assertTrue(view.hasCalledOnKeyMultiple());
}
@@ -4655,6 +4635,10 @@
mHasChildDrawableStateChanged = false;
mHasBroughtChildToFront = false;
}
+
+ public void childOverlayStateChanged(View child) {
+
+ }
}
private final class OnCreateContextMenuListenerImpl implements OnCreateContextMenuListener {
diff --git a/tests/tests/view/src/android/view/cts/WindowTest.java b/tests/tests/view/src/android/view/cts/WindowTest.java
index 527f444..0e31888 100644
--- a/tests/tests/view/src/android/view/cts/WindowTest.java
+++ b/tests/tests/view/src/android/view/cts/WindowTest.java
@@ -39,11 +39,13 @@
import android.util.DisplayMetrics;
import android.view.accessibility.AccessibilityEvent;
import android.view.Gravity;
+import android.view.InputQueue;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
+import android.view.SurfaceHolder;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
@@ -1243,6 +1245,14 @@
public void setDefaultWindowFormat(int format) {
super.setDefaultWindowFormat(format);
}
+
+ @Override
+ public void takeSurface(SurfaceHolder.Callback2 callback) {
+ }
+
+ @Override
+ public void takeInputQueue(InputQueue.Callback callback) {
+ }
}
private class MockWindowCallback implements Window.Callback {
diff --git a/tests/tests/view/src/android/view/inputmethod/cts/InputConnectionWrapperTest.java b/tests/tests/view/src/android/view/inputmethod/cts/InputConnectionWrapperTest.java
index 896e99f..bdee05a 100644
--- a/tests/tests/view/src/android/view/inputmethod/cts/InputConnectionWrapperTest.java
+++ b/tests/tests/view/src/android/view/inputmethod/cts/InputConnectionWrapperTest.java
@@ -97,6 +97,11 @@
args = {int.class, int.class}
),
@TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "getSelectedText",
+ args = {int.class}
+ ),
+ @TestTargetNew(
level = TestLevel.COMPLETE,
method = "getCursorCapsMode",
args = {int.class}
@@ -127,6 +132,11 @@
args = {CharSequence.class, int.class}
),
@TestTargetNew(
+ level = TestLevel.COMPLETE,
+ method = "setComposingRegion",
+ args = {int.class, int.class}
+ ),
+ @TestTargetNew(
level = TestLevel.COMPLETE,
method = "sendKeyEvent",
args = {KeyEvent.class}
@@ -184,6 +194,10 @@
assertTrue(inputConnection.isSetComposingTextCalled);
wrapper.setSelection(0, 10);
assertTrue(inputConnection.isSetSelectionCalled);
+ wrapper.getSelectedText(0);
+ assertTrue(inputConnection.isGetSelectedTextCalled);
+ wrapper.setComposingRegion(0, 3);
+ assertTrue(inputConnection.isSetComposingRegionCalled);
}
private class MockInputConnection implements InputConnection {
@@ -198,12 +212,14 @@
public boolean isGetExtractedTextCalled;
public boolean isGetTextAfterCursorCalled;
public boolean isGetTextBeforeCursorCalled;
+ public boolean isGetSelectedTextCalled;
public boolean isPerformContextMenuActionCalled;
public boolean isPerformEditorActionCalled;
public boolean isPerformPrivateCommandCalled;
public boolean isReportFullscreenModeCalled;
public boolean isSendKeyEventCalled;
public boolean isSetComposingTextCalled;
+ public boolean isSetComposingRegionCalled;
public boolean isSetSelectionCalled;
public boolean beginBatchEdit() {
@@ -261,6 +277,11 @@
return null;
}
+ public CharSequence getSelectedText(int flags) {
+ isGetSelectedTextCalled = true;
+ return null;
+ }
+
public boolean performContextMenuAction(int id) {
isPerformContextMenuActionCalled = true;
return false;
@@ -291,6 +312,11 @@
return false;
}
+ public boolean setComposingRegion(int start, int end) {
+ isSetComposingRegionCalled = true;
+ return false;
+ }
+
public boolean setSelection(int start, int end) {
isSetSelectionCalled = true;
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 554acd8..b9d054f 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -1732,22 +1732,6 @@
});
}
- @TestTargetNew(
- level = TestLevel.SUFFICIENT,
- method = "performLongClick",
- args = {}
- )
- public void testPerformLongClick() throws InterruptedException {
- String form = "<p><form><input type=\"text\" name=\"Test\"><br>"
- + "<input type=\"submit\" value=\"Submit\"></form></p>";
- mWebView.loadDataWithBaseURL("fake://home", "<html><body>" + form
- + "</body></html>", "text/html", "UTF-8", null);
- waitForLoadComplete(mWebView, TEST_TIMEOUT);
-
- mWebView.performLongClick();
- // no simple way to check the effect of a long click
- }
-
@TestTargets({
@TestTargetNew(
level = TestLevel.COMPLETE,
diff --git a/tests/tests/widget/src/android/widget/cts/CursorTreeAdapterTest.java b/tests/tests/widget/src/android/widget/cts/CursorTreeAdapterTest.java
index 0927b61..e448a97 100644
--- a/tests/tests/widget/src/android/widget/cts/CursorTreeAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CursorTreeAdapterTest.java
@@ -79,12 +79,20 @@
mDatabase.execSQL("CREATE TABLE child1 (_id INTEGER PRIMARY KEY, value TEXT);");
mDatabase.execSQL("INSERT INTO child1 (value) VALUES ('" + CHILD_VALUE_ONE + "');");
mDatabase.execSQL("INSERT INTO child1 (value) VALUES ('" + CHILD_VALUE_TWO + "');");
+ return getChild1Cursor();
+ }
+
+ private Cursor getChild1Cursor() {
return mDatabase.query("child1", VALUE_PROJECTION, null, null, null, null, null);
}
private Cursor createChild2Cursor() {
mDatabase.execSQL("CREATE TABLE child2 (_id INTEGER PRIMARY KEY, value TEXT);");
mDatabase.execSQL("INSERT INTO child2 (value) VALUES ('" + CHILD_VALUE_THREE + "');");
+ return getChild2Cursor();
+ }
+
+ private Cursor getChild2Cursor() {
return mDatabase.query("child2", VALUE_PROJECTION, null, null, null, null, null);
}
@@ -679,7 +687,7 @@
level = TestLevel.COMPLETE,
notes = "Test {@link CursorAdapter#getChildView(int, int, boolean, View, ViewGroup)}",
method = "getChildView",
- args = {int.class, int.class, boolean.class, android.view.View.class,
+ args = {int.class, int.class, boolean.class, android.view.View.class,
android.view.ViewGroup.class}
)
public void testGetChildView() {
@@ -792,9 +800,15 @@
if (0 == groupCursor.getPosition()) {
mHasAddedChild1IntoCache = true;
+ if (mChildCursor1.isClosed()) {
+ mChildCursor1 = getChild1Cursor();
+ }
return mChildCursor1;
} else if (1 == groupCursor.getPosition()) {
mHasAddedChild2IntoCache = true;
+ if (mChildCursor2.isClosed()) {
+ mChildCursor2 = getChild2Cursor();
+ }
return mChildCursor2;
}
return null;
diff --git a/tests/tests/widget/src/android/widget/cts/GridViewTest.java b/tests/tests/widget/src/android/widget/cts/GridViewTest.java
index 65045d8..40684c9 100644
--- a/tests/tests/widget/src/android/widget/cts/GridViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/GridViewTest.java
@@ -215,11 +215,11 @@
mInstrumentation.waitForIdleSync();
assertEquals(0, mGridView.getSelectedItemPosition());
- KeyEvent event = new KeyEvent(KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_DPAD_RIGHT);
+ KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT);
mInstrumentation.sendKeySync(event);
assertEquals(1, mGridView.getSelectedItemPosition());
- event = new KeyEvent(KeyEvent.ACTION_MULTIPLE, KeyEvent.KEYCODE_DPAD_LEFT);
+ event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT);
mInstrumentation.sendKeySync(event);
assertEquals(0, mGridView.getSelectedItemPosition());
@@ -535,7 +535,7 @@
@TestTargetNew(
level = TestLevel.COMPLETE,
method = "attachLayoutAnimationParameters",
- args = {android.view.View.class, android.view.ViewGroup.LayoutParams.class, int.class,
+ args = {android.view.View.class, android.view.ViewGroup.LayoutParams.class, int.class,
int.class}
)
public void testAttachLayoutAnimationParameters() {
diff --git a/tests/tests/widget/src/android/widget/cts/ImageSwitcherTest.java b/tests/tests/widget/src/android/widget/cts/ImageSwitcherTest.java
index 9e32748..a7667ba 100644
--- a/tests/tests/widget/src/android/widget/cts/ImageSwitcherTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageSwitcherTest.java
@@ -136,18 +136,20 @@
imageSwitcher.setImageURI(uri);
assertSame(iv1, imageSwitcher.getCurrentView());
- Bitmap testImageBitmap = WidgetTestUtils.getUnscaledBitmap(getContext().getResources(),
- R.raw.testimage);
BitmapDrawable currViewBitmap =
(BitmapDrawable) ((ImageView) imageSwitcher.getCurrentView()).getDrawable();
+ Bitmap testImageBitmap = WidgetTestUtils.getUnscaledAndDitheredBitmap(
+ getContext().getResources(), R.raw.testimage,
+ currViewBitmap.getBitmap().getConfig());
WidgetTestUtils.assertEquals(testImageBitmap, currViewBitmap.getBitmap());
createSampleImage(imagefile, R.raw.scenery);
uri = Uri.parse(imagefile.getPath());
imageSwitcher.setImageURI(uri);
assertSame(iv, imageSwitcher.getCurrentView());
- Bitmap sceneryImageBitmap = WidgetTestUtils.getUnscaledBitmap(getContext().getResources(),
- R.raw.scenery);
+ Bitmap sceneryImageBitmap = WidgetTestUtils.getUnscaledAndDitheredBitmap(
+ getContext().getResources(), R.raw.scenery,
+ currViewBitmap.getBitmap().getConfig());
currViewBitmap =
(BitmapDrawable) ((ImageView) imageSwitcher.getCurrentView()).getDrawable();
WidgetTestUtils.assertEquals(sceneryImageBitmap, currViewBitmap.getBitmap());
diff --git a/tests/tests/widget/src/android/widget/cts/ImageViewTest.java b/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
index 5214b50..0777259 100644
--- a/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
@@ -276,10 +276,12 @@
assertTrue(mImageView.isLayoutRequested());
assertNotNull(mImageView.getDrawable());
- Bitmap testimageBitmap = WidgetTestUtils.getUnscaledBitmap(mActivity.getResources(),
- R.raw.testimage);
Drawable imageViewDrawable = mImageView.getDrawable();
BitmapDrawable imageViewBitmap = (BitmapDrawable) imageViewDrawable;
+ Bitmap.Config viewConfig = imageViewBitmap.getBitmap().getConfig();
+ Bitmap testimageBitmap = WidgetTestUtils.getUnscaledAndDitheredBitmap(
+ mActivity.getResources(), R.raw.testimage, viewConfig);
+
WidgetTestUtils.assertEquals(testimageBitmap, imageViewBitmap.getBitmap());
}
diff --git a/tests/tests/widget/src/android/widget/cts/SimpleAdapterTest.java b/tests/tests/widget/src/android/widget/cts/SimpleAdapterTest.java
index 6fb7063..d20582b 100644
--- a/tests/tests/widget/src/android/widget/cts/SimpleAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SimpleAdapterTest.java
@@ -410,10 +410,10 @@
mSimpleAdapter.setViewImage(view, SimpleCursorAdapterTest.createTestImage(mContext,
"testimage", com.android.cts.stub.R.raw.testimage));
assertNotNull(view.getDrawable());
- Bitmap testBitmap = WidgetTestUtils.getUnscaledBitmap(mContext.getResources(),
- com.android.cts.stub.R.raw.testimage);
- WidgetTestUtils.assertEquals(testBitmap,
- ((BitmapDrawable) view.getDrawable()).getBitmap());
+ Bitmap actualBitmap = ((BitmapDrawable) view.getDrawable()).getBitmap();
+ Bitmap testBitmap = WidgetTestUtils.getUnscaledAndDitheredBitmap(mContext.getResources(),
+ com.android.cts.stub.R.raw.testimage, actualBitmap.getConfig());
+ WidgetTestUtils.assertEquals(testBitmap, actualBitmap);
} finally {
SimpleCursorAdapterTest.destroyTestImage(mContext,"testimage");
}
diff --git a/tests/tests/widget/src/android/widget/cts/SimpleCursorAdapterTest.java b/tests/tests/widget/src/android/widget/cts/SimpleCursorAdapterTest.java
index 8f32228..08e425a 100644
--- a/tests/tests/widget/src/android/widget/cts/SimpleCursorAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SimpleCursorAdapterTest.java
@@ -256,10 +256,10 @@
mSimpleCursorAdapter.setViewImage(view,
createTestImage(mContext, SAMPLE_IMAGE_NAME, testimgRawId));
assertNotNull(view.getDrawable());
- Bitmap testBitmap = WidgetTestUtils.getUnscaledBitmap(mContext.getResources(),
- testimgRawId);
- WidgetTestUtils.assertEquals(testBitmap,
- ((BitmapDrawable) view.getDrawable()).getBitmap());
+ Bitmap actualBitmap = ((BitmapDrawable) view.getDrawable()).getBitmap();
+ Bitmap testBitmap = WidgetTestUtils.getUnscaledAndDitheredBitmap(mContext.getResources(),
+ testimgRawId, actualBitmap.getConfig());
+ WidgetTestUtils.assertEquals(testBitmap, actualBitmap);
} finally {
destroyTestImage(mContext, SAMPLE_IMAGE_NAME);
}
diff --git a/tests/tests/widget/src/android/widget/cts/SimpleCursorTreeAdapterTest.java b/tests/tests/widget/src/android/widget/cts/SimpleCursorTreeAdapterTest.java
index 7295e75..8e6f0f3 100644
--- a/tests/tests/widget/src/android/widget/cts/SimpleCursorTreeAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SimpleCursorTreeAdapterTest.java
@@ -83,24 +83,24 @@
level = TestLevel.COMPLETE,
notes = "Test constructors",
method = "SimpleCursorTreeAdapter",
- args = {android.content.Context.class, android.database.Cursor.class, int.class,
- int.class, java.lang.String[].class, int[].class, int.class, int.class,
+ args = {android.content.Context.class, android.database.Cursor.class, int.class,
+ int.class, java.lang.String[].class, int[].class, int.class, int.class,
java.lang.String[].class, int[].class}
),
@TestTargetNew(
level = TestLevel.COMPLETE,
notes = "Test constructors",
method = "SimpleCursorTreeAdapter",
- args = {android.content.Context.class, android.database.Cursor.class, int.class,
- int.class, java.lang.String[].class, int[].class, int.class,
+ args = {android.content.Context.class, android.database.Cursor.class, int.class,
+ int.class, java.lang.String[].class, int[].class, int.class,
java.lang.String[].class, int[].class}
),
@TestTargetNew(
level = TestLevel.COMPLETE,
notes = "Test constructors",
method = "SimpleCursorTreeAdapter",
- args = {android.content.Context.class, android.database.Cursor.class, int.class,
- java.lang.String[].class, int[].class, int.class, java.lang.String[].class,
+ args = {android.content.Context.class, android.database.Cursor.class, int.class,
+ java.lang.String[].class, int[].class, int.class, java.lang.String[].class,
int[].class}
)
})
@@ -122,7 +122,7 @@
@TestTargetNew(
level = TestLevel.COMPLETE,
method = "bindChildView",
- args = {android.view.View.class, android.content.Context.class,
+ args = {android.view.View.class, android.content.Context.class,
android.database.Cursor.class, boolean.class}
)
public void testBindChildView() {
@@ -146,7 +146,7 @@
@TestTargetNew(
level = TestLevel.COMPLETE,
method = "bindGroupView",
- args = {android.view.View.class, android.content.Context.class,
+ args = {android.view.View.class, android.content.Context.class,
android.database.Cursor.class, boolean.class}
)
// The param context and isExpanded is never readed.
@@ -183,7 +183,7 @@
// color drawable
ImageView view = new ImageView(mContext);
assertNull(view.getDrawable());
- mSimpleCursorTreeAdapter.setViewImage(view,
+ mSimpleCursorTreeAdapter.setViewImage(view,
String.valueOf(com.android.cts.stub.R.drawable.scenery));
BitmapDrawable d = (BitmapDrawable) mContext.getResources().getDrawable(
com.android.cts.stub.R.drawable.scenery);
@@ -213,10 +213,10 @@
mSimpleCursorTreeAdapter.setViewImage(view,
SimpleCursorAdapterTest.createTestImage(mContext, SAMPLE_IMAGE_NAME,
com.android.cts.stub.R.raw.testimage));
- Bitmap test = WidgetTestUtils.getUnscaledBitmap(mContext.getResources(),
- com.android.cts.stub.R.raw.testimage);
- WidgetTestUtils.assertEquals(test,
- ((BitmapDrawable) view.getDrawable()).getBitmap());
+ Bitmap actualBitmap = ((BitmapDrawable) view.getDrawable()).getBitmap();
+ Bitmap test = WidgetTestUtils.getUnscaledAndDitheredBitmap(mContext.getResources(),
+ com.android.cts.stub.R.raw.testimage, actualBitmap.getConfig());
+ WidgetTestUtils.assertEquals(test, actualBitmap);
} finally {
SimpleCursorAdapterTest.destroyTestImage(mContext, SAMPLE_IMAGE_NAME);
}
diff --git a/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoInstrument.java b/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoInstrument.java
index 78d9597..b9d7b95 100644
--- a/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoInstrument.java
+++ b/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoInstrument.java
@@ -40,7 +40,9 @@
private static final String TAG = "DeviceInfoInstrument";
- private static final String OPEN_GL_ES_VERSION = "opengles_version";
+ // constants for device info attributes to be sent as instrumentation keys
+ // these values should correspond to attributes defined in cts_result.xsd
+ private static final String OPEN_GL_ES_VERSION = "openGlEsVersion";
private static final String PROCESSES = "processes";
private static final String FEATURES = "features";
private static final String PHONE_NUMBER = "phoneNumber";
@@ -50,27 +52,24 @@
private static final String NETWORK = "network";
public static final String KEYPAD = "keypad";
public static final String NAVIGATION = "navigation";
- public static final String TOUCH_SCREEN = "touch_screen";
- private static final String SCREEN_Y_DENSITY = "screen_Y_density";
- private static final String SCREEN_X_DENSITY = "screen_X_density";
- private static final String SCREEN_DENSITY = "screen_density";
+ public static final String TOUCH_SCREEN = "touch";
+ private static final String SCREEN_Y_DENSITY = "Ydpi";
+ private static final String SCREEN_X_DENSITY = "Xdpi";
private static final String SCREEN_HEIGHT = "screen_height";
private static final String SCREEN_WIDTH = "screen_width";
- private static final String VERSION_SDK = "version_sdk";
- private static final String VERSION_RELEASE = "version_release";
- private static final String VERSION_INCREMENTAL = "version_incremental";
+ private static final String VERSION_SDK = "androidPlatformVersion";
+ private static final String VERSION_RELEASE = "buildVersion";
private static final String BUILD_ABI = "build_abi";
private static final String BUILD_ABI2 = "build_abi2";
private static final String BUILD_FINGERPRINT = "build_fingerprint";
- private static final String BUILD_TAGS = "build_tags";
private static final String BUILD_TYPE = "build_type";
private static final String BUILD_MODEL = "build_model";
private static final String BUILD_BRAND = "build_brand";
private static final String BUILD_MANUFACTURER = "build_manufacturer";
private static final String BUILD_BOARD = "build_board";
private static final String BUILD_DEVICE = "build_device";
- private static final String PRODUCT_NAME = "product_name";
- private static final String BUILD_ID = "build_id";
+ private static final String PRODUCT_NAME = "buildName";
+ private static final String BUILD_ID = "buildID";
private static Bundle mResults = new Bundle();
public DeviceInfoInstrument() {
@@ -93,12 +92,10 @@
addResult(BUILD_BRAND, Build.BRAND);
addResult(BUILD_MODEL, Build.MODEL);
addResult(BUILD_TYPE, Build.TYPE);
- addResult(BUILD_TAGS, Build.TAGS);
addResult(BUILD_FINGERPRINT, Build.FINGERPRINT);
addResult(BUILD_ABI, Build.CPU_ABI);
addResult(BUILD_ABI2, Build.CPU_ABI2);
- addResult(VERSION_INCREMENTAL, Build.VERSION.INCREMENTAL);
addResult(VERSION_RELEASE, Build.VERSION.RELEASE);
addResult(VERSION_SDK, Build.VERSION.SDK);
@@ -109,7 +106,6 @@
d.getMetrics(metrics);
addResult(SCREEN_WIDTH, metrics.widthPixels);
addResult(SCREEN_HEIGHT, metrics.heightPixels);
- addResult(SCREEN_DENSITY, metrics.density);
addResult(SCREEN_X_DENSITY, metrics.xdpi);
addResult(SCREEN_Y_DENSITY, metrics.ydpi);
diff --git a/tools/host/etc/cts b/tools/host/etc/cts
index c368db2..bb1fa2a 100755
--- a/tools/host/etc/cts
+++ b/tools/host/etc/cts
@@ -17,7 +17,7 @@
CTS_SH=cts
CTS_LIB=cts.jar
-DDMS_LIB=ddmlib.jar
+DDMS_LIB=ddmlib-prebuilt.jar
JUNIT_LIB=junit.jar
HOSTTEST_LIB=hosttestlib.jar
CTS_TEST_ANNOTATIONS_HOST_LIB=CtsTestAnnotationsHostLib.jar
@@ -38,15 +38,13 @@
BINARY_DIR=tools
JAR_DIR=tools/lib
else if [ ! -f ${ANDROID_ROOT}/bin/${ADB_TOOLS} ]; then
- echo "Please set your Android Framework root path."
- echo "Define \"ANDROID_ROOT\" variable"
+ echo "Missing ${ANDROID_ROOT}/bin/${ADB_TOOLS}"
exit -1;
fi;
fi;
if [ ! -f ${ANDROID_ROOT}/${JAR_DIR}/${DDMS_LIB} ]; then
- echo "Please set your Android Framework root path."
- echo "Define \"ANDROID_ROOT\" variable"
+ echo "Missing ${ANDROID_ROOT}/${JAR_DIR}/${DDMS_LIB}"
exit -1;
fi;
diff --git a/tools/host/src/Android.mk b/tools/host/src/Android.mk
index 1fd8159..5ad3998 100644
--- a/tools/host/src/Android.mk
+++ b/tools/host/src/Android.mk
@@ -21,7 +21,7 @@
LOCAL_JAR_MANIFEST := ../etc/manifest.txt
LOCAL_JAVA_LIBRARIES := \
- ddmlib junit hosttestlib CtsTestAnnotationsHostLib
+ ddmlib-prebuilt junit hosttestlib CtsTestAnnotationsHostLib
LOCAL_MODULE := cts
diff --git a/tools/host/src/com/android/cts/DeviceManager.java b/tools/host/src/com/android/cts/DeviceManager.java
index c164ac1..c794332 100644
--- a/tools/host/src/com/android/cts/DeviceManager.java
+++ b/tools/host/src/com/android/cts/DeviceManager.java
@@ -16,8 +16,10 @@
package com.android.cts;
+import com.android.ddmlib.AdbCommandRejectedException;
import com.android.ddmlib.AndroidDebugBridge;
import com.android.ddmlib.IDevice;
+import com.android.ddmlib.TimeoutException;
import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
import java.io.IOException;
@@ -230,6 +232,10 @@
mSemaphore.release();
} catch (IOException e) {
// FIXME: handle failed connection to device.
+ } catch (TimeoutException e) {
+ // FIXME: handle failed connection to device.
+ } catch (AdbCommandRejectedException e) {
+ // FIXME: handle failed connection to device.
}
}
}
diff --git a/tools/host/src/com/android/cts/ReferenceAppTestPackage.java b/tools/host/src/com/android/cts/ReferenceAppTestPackage.java
index 1b32576..0b6aa50 100644
--- a/tools/host/src/com/android/cts/ReferenceAppTestPackage.java
+++ b/tools/host/src/com/android/cts/ReferenceAppTestPackage.java
@@ -16,8 +16,10 @@
package com.android.cts;
+import com.android.ddmlib.AdbCommandRejectedException;
import com.android.ddmlib.MultiLineReceiver;
import com.android.ddmlib.RawImage;
+import com.android.ddmlib.TimeoutException;
import com.android.ddmlib.log.LogReceiver.ILogListener;
import com.android.ddmlib.log.LogReceiver.LogEntry;
@@ -199,6 +201,10 @@
}
} catch (IOException e) {
Log.e("Error taking snapshot! " + cmdArgs, e);
+ } catch (TimeoutException e) {
+ Log.e("Error taking snapshot! " + cmdArgs, e);
+ } catch (AdbCommandRejectedException e) {
+ Log.e("Error taking snapshot! " + cmdArgs, e);
}
}
});
diff --git a/tools/host/src/com/android/cts/TestDevice.java b/tools/host/src/com/android/cts/TestDevice.java
index bb879aa..83a5763 100644
--- a/tools/host/src/com/android/cts/TestDevice.java
+++ b/tools/host/src/com/android/cts/TestDevice.java
@@ -16,6 +16,7 @@
package com.android.cts;
+import com.android.ddmlib.AdbCommandRejectedException;
import com.android.ddmlib.Client;
import com.android.ddmlib.ClientData;
import com.android.ddmlib.IDevice;
@@ -23,13 +24,16 @@
import com.android.ddmlib.MultiLineReceiver;
import com.android.ddmlib.NullOutputReceiver;
import com.android.ddmlib.RawImage;
+import com.android.ddmlib.ShellCommandUnresponsiveException;
+import com.android.ddmlib.SyncException;
import com.android.ddmlib.SyncService;
import com.android.ddmlib.SyncService.ISyncProgressMonitor;
-import com.android.ddmlib.SyncService.SyncResult;
+import com.android.ddmlib.TimeoutException;
import com.android.ddmlib.log.LogReceiver;
import com.android.ddmlib.log.LogReceiver.ILogListener;
import java.io.BufferedReader;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -101,6 +105,8 @@
try {
mDevice.runLogService("main", logReceiver);
} catch (IOException e) {
+ } catch (TimeoutException e) {
+ } catch (AdbCommandRejectedException e) {
}
}
@@ -136,6 +142,10 @@
mSyncService = mDevice.getSyncService();
} catch (IOException e) {
// FIXME: handle failed connection.
+ } catch (TimeoutException e) {
+ // FIXME: handle failed connection.
+ } catch (AdbCommandRejectedException e) {
+ // FIXME: handle failed connection.
}
mBatchModeResultParser = null;
mUninstallObserver = new PackageActionObserver(ACTION_UNINSTALL);
@@ -391,9 +401,11 @@
* Store the build information of a device
*/
public static final class DeviceParameterCollector{
- public static final String PRODUCT_NAME = "product_name";
- public static final String BUILD_VERSION = "version_release";
- public static final String BUILD_ID = "build_id";
+ // the device info keys expected to be sent from device info instrumentation
+ // these constants should match exactly with those defined in DeviceInfoInstrument.jaa
+ public static final String PRODUCT_NAME = "buildName";
+ public static final String BUILD_VERSION = "buildVersion";
+ public static final String BUILD_ID = "buildID";
public static final String BUILD_FINGERPRINT = "build_fingerprint";
public static final String BUILD_TAGS = "build_tags";
public static final String BUILD_TYPE = "build_type";
@@ -406,13 +418,12 @@
public static final String BUILD_ABI2 = "build_abi2";
public static final String SCREEN_HEIGHT = "screen_height";
public static final String SCREEN_WIDTH = "screen_width";
- public static final String SCREEN_DENSITY = "screen_density";
public static final String SERIAL_NUMBER = "serialNumber";
- public static final String VERSION_SDK = "version_sdk";
+ public static final String VERSION_SDK = "androidPlatformVersion";
public static final String LOCALES = "locales";
- public static final String SCREEN_Y_DENSITY = "screen_Y_density";
- public static final String SCREEN_X_DENSITY = "screen_X_density";
- public static final String TOUCH_SCREEN = "touch_screen";
+ public static final String SCREEN_Y_DENSITY = "Ydpi";
+ public static final String SCREEN_X_DENSITY = "Xdpi";
+ public static final String TOUCH_SCREEN = "touch";
public static final String NAVIGATION = "navigation";
public static final String KEYPAD = "keypad";
public static final String NETWORK = "network";
@@ -421,7 +432,7 @@
public static final String PHONE_NUMBER = "phoneNumber";
public static final String FEATURES = "features";
public static final String PROCESSES = "processes";
- public static final String OPEN_GL_ES_VERSION = "opengles_version";
+ public static final String OPEN_GL_ES_VERSION = "openGlEsVersion";
private HashMap<String, String> mInfoMap;
@@ -933,10 +944,16 @@
* @param remotePath The remote path.
*/
public void pushFile(String localPath, String remotePath) {
- SyncResult result = mSyncService.pushFile(localPath, remotePath,
- new PushMonitor());
- if (result.getCode() != SyncService.RESULT_OK) {
- Log.e("Uploading file failed: " + result.getMessage(), null);
+ try {
+ mSyncService.pushFile(localPath, remotePath, new PushMonitor());
+ } catch (TimeoutException e) {
+ Log.e("Uploading file failed: timeout", null);
+ } catch (SyncException e) {
+ Log.e("Uploading file failed: " + e.getMessage(), null);
+ } catch (FileNotFoundException e) {
+ Log.e("Uploading file failed: " + e.getMessage(), null);
+ } catch (IOException e) {
+ Log.e("Uploading file failed: " + e.getMessage(), null);
}
}
@@ -1691,10 +1708,19 @@
@Override
public void run() {
try {
- mDevice.executeShellCommand(cmd, receiver);
+ mDevice.executeShellCommand(cmd, receiver, 0);
} catch (IOException e) {
Log.e(String.format("Failed to execute shell command %s on device %s", cmd,
mDevice.getSerialNumber()), e);
+ } catch (TimeoutException e) {
+ Log.e(String.format("Failed to execute shell command %s on device %s", cmd,
+ mDevice.getSerialNumber()), e);
+ } catch (AdbCommandRejectedException e) {
+ Log.e(String.format("Failed to execute shell command %s on device %s", cmd,
+ mDevice.getSerialNumber()), e);
+ } catch (ShellCommandUnresponsiveException e) {
+ Log.e(String.format("Failed to execute shell command %s on device %s", cmd,
+ mDevice.getSerialNumber()), e);
}
}
}.start();
@@ -1912,8 +1938,11 @@
*
* @return the screenshot
* @throws IOException
+ * @throws AdbCommandRejectedException
+ * @throws TimeoutException
*/
- public RawImage getScreenshot() throws IOException {
+ public RawImage getScreenshot() throws IOException, TimeoutException,
+ AdbCommandRejectedException {
return mDevice.getScreenshot();
}
}
diff --git a/tools/host/src/com/android/cts/Version.java b/tools/host/src/com/android/cts/Version.java
index 4664a3e..fead909 100644
--- a/tools/host/src/com/android/cts/Version.java
+++ b/tools/host/src/com/android/cts/Version.java
@@ -18,12 +18,12 @@
public class Version {
// The CTS version string
- private static final String version = "2.2_r3";
-
+ private static final String version = "2.2_r1";
+
private Version() {
// no instances allowed
}
-
+
public static String asString() {
return version;
}
diff --git a/tools/tradefed-host/.classpath b/tools/tradefed-host/.classpath
new file mode 100644
index 0000000..a61e37c
--- /dev/null
+++ b/tools/tradefed-host/.classpath
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="res"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/ddmlib"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/tradefederation"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/hosttestlib"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/tools/tradefed-host/.project b/tools/tradefed-host/.project
new file mode 100644
index 0000000..990c63e
--- /dev/null
+++ b/tools/tradefed-host/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>cts-tradefed-host</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/tools/tradefed-host/Android.mk b/tools/tradefed-host/Android.mk
new file mode 100644
index 0000000..c1e5c54
--- /dev/null
+++ b/tools/tradefed-host/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2010 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)
+
+# Only compile source java files in this lib.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_JAVA_RESOURCE_DIRS := res
+
+LOCAL_MODULE := cts-tradefed
+LOCAL_MODULE_TAGS := optional
+LOCAL_JAVA_LIBRARIES := ddmlib-prebuilt tradefed-prebuilt hosttestlib
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+# Build all sub-directories
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/tools/tradefed-host/res/config/cts.xml b/tools/tradefed-host/res/config/cts.xml
new file mode 100644
index 0000000..d98c7fb
--- /dev/null
+++ b/tools/tradefed-host/res/config/cts.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<configuration
+ description="Runs a CTS plan from a pre-existing CTS installation">
+
+ <build_provider class="com.android.cts.tradefed.targetsetup.CtsBuildProvider" />
+ <device_recovery class="com.android.tradefed.device.WaitDeviceRecovery" />
+ <target_preparer class="com.android.cts.tradefed.targetsetup.CtsSetup" />
+ <test class="com.android.cts.tradefed.testtype.PlanTest" />
+ <logger class="com.android.tradefed.log.FileLogger" />
+ <result_reporter class="com.android.cts.tradefed.result.CtsXmlResultReporter" />
+
+</configuration>
diff --git a/tools/tradefed-host/res/result/cts_result.css b/tools/tradefed-host/res/result/cts_result.css
new file mode 100644
index 0000000..d7ce510
--- /dev/null
+++ b/tools/tradefed-host/res/result/cts_result.css
@@ -0,0 +1,234 @@
+/* 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.
+*/
+
+body {
+ font-family:arial,sans-serif;
+ color:#000;
+ font-size:13px;
+ color:#333;
+ padding:10;
+ margin:10;
+}
+
+table {
+ font-size:1em;
+ margin:0 0 1em;
+ padding:0;
+ border-collapse:collapse;
+ border-width:0;
+ empty-cells:show;
+ width: 95%;
+}
+
+/* Report logo and device name */
+#title table {
+ padding:5px;
+ border-width: 0px;
+ margin-left:auto;
+ margin-right:auto;
+ vertical-align:middle;
+}
+
+/* Device and test plan summary below the title */
+#summary table {
+ background-color: rgb(212, 233, 169);
+ -moz-border-radius:5px;
+ border-radius:5px;
+ padding:5px;
+ border-color: #A5C639 #A5C639 #A5C639 #A5C639;
+ border-width: 0px 0px 0px 0px;
+ margin-left:auto;
+ margin-right:auto;
+ width:80%;
+}
+
+#summary th {
+ background-color: #A5C639;
+ font-size:1.2em;
+ height: 2em;
+ width: 50%;
+}
+
+#summary td {
+ border-width: 0px 0px 0px 0px;
+ border-color: gray;
+ border-style: inset;
+ font-size:1em;
+ vertical-align: top;
+}
+
+#summaryinfo table {
+ background-color: rgb(212, 233, 169);
+ padding:5px;
+ border-width:0;
+ margin-left:auto;
+ margin-right:auto;
+}
+
+#summaryinfo td {
+ padding:1px;
+ border-width: 0px 0px 0px 0px;
+ vertical-align: top;
+}
+
+/* The test summary */
+#testsummary table {
+ background-color: rgb(212, 233, 169);
+ padding:5px;
+ border-width:1;
+ border-color: #A5C639;
+ margin-left:auto;
+ margin-right:auto;
+ width: 40%;
+}
+
+#testsummary th {
+ background-color: #A5C639;
+ border-width: 1px;
+ border-color: gray;
+ border-style: outset;
+ height: 2em;
+}
+
+#testsummary td {
+ border-width: 1px;
+ border-color: #A5C639;
+ border-style: outset;
+ text-align: center;
+}
+
+/* The test details */
+#testdetail table {
+ background-color: rgb(212, 233, 169);
+ padding:5px;
+ border-width:1;
+ border-color: #A5C639;
+ margin-left:auto;
+ margin-right:auto;
+ width: 95%;
+ table-layout:fixed;
+ vertical-align: top;
+}
+
+#testdetail th {
+ background-color: #A5C639;
+ border-width: 1px;
+ border-color: gray;
+ border-style: outset;
+ height: 2em;
+}
+
+#testdetail td {
+ border-width: 1px;
+ border-color: #A5C639;
+ border-style: outset;
+ text-align: left;
+ vertical-align: top;
+ padding:1;
+}
+
+/* The test package name */
+#none table {
+ border-width:0;
+ border-color: white;
+ background-color: white;
+ text-align:left;
+ border-collapse:collapse;
+}
+
+#none td {
+ border-width:0;
+ border-color: white;
+ background-color: white;
+ text-align:left;
+ border-collapse:collapse;
+ font-weight:bold;
+}
+
+/* Test cell details */
+td.failed {
+ background-color: #FA5858;
+ font-weight:bold;
+ vertical-align: top;
+ text-align: center;
+}
+
+td.failuredetails {
+ text-align: left;
+}
+
+td.pass {
+ text-align: center;
+ margin-left:auto;
+ margin-right:auto;
+}
+
+td.timeout, td.omitted, td.notExecuted {
+ background-color: #A5C639;
+ vertical-align: top;
+ text-align: center;
+}
+
+td.testname {
+ border-width: 1px;
+ border-color: #A5C639;
+ border-style: outset;
+ text-align: left;
+ vertical-align: top;
+ padding:1;
+ overflow:hidden;
+}
+
+td.testcase {
+ border-width: 1px;
+ border-color: #A5C639;
+ border-style: outset;
+ text-align: left;
+ vertical-align: top;
+ padding:1;
+ overflow:hidden;
+ font-weight:bold;
+}
+
+td.testcasespacer {
+ border-width: 1px;
+ border-color: #A5C639;
+ border-style: outset;
+ text-align: left;
+ vertical-align: top;
+ padding:1;
+ overflow:hidden;
+ font-weight:bold;
+}
+
+td.testsuite {
+ border-width: 1px;
+ border-color: #A5C639;
+ border-style: outset;
+ text-align: left;
+ vertical-align: top;
+ padding:1;
+ overflow:hidden;
+ font-weight:bold;
+}
+
+#details {
+ white-space: pre-wrap; /* css-3 */
+ white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
+ white-space: -pre-wrap; /* Opera 4-6 */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ word-wrap: break-word; /* Internet Explorer 5.5+ */
+ overflow:auto;
+}
diff --git a/tools/tradefed-host/res/result/cts_result.xsd b/tools/tradefed-host/res/result/cts_result.xsd
new file mode 100644
index 0000000..f2fc3a8
--- /dev/null
+++ b/tools/tradefed-host/res/result/cts_result.xsd
@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Copyright (C) 2009 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.
+ -->
+
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="http://compatibility.android.com/cts_result/2.0"
+ xmlns="http://compatibility.android.com/cts_result/2.0"
+ elementFormDefault="qualified">
+
+<xs:element name="TestResult">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="DeviceInfo" type="deviceInfoType"/>
+ <xs:element name="HostInfo" type="hostInfoType"/>
+ <xs:element name="Summary" type="summaryType"/>
+ <xs:element name="TestPackage" type="testPackageType" maxOccurs="unbounded" minOccurs="1"/>
+ </xs:sequence>
+ <xs:attribute name="starttime" type="xs:string"/>
+ <xs:attribute name="endtime" type="xs:string"/>
+ <xs:attribute name="testPlan" type="xs:string"/>
+ <xs:attribute name="version" type="xs:string"/>
+ <xs:attribute name="profile" type="xs:string"/>
+ </xs:complexType>
+</xs:element>
+
+<xs:complexType name="deviceInfoType">
+ <xs:sequence>
+ <xs:element name="Screen">
+ <xs:complexType>
+ <xs:attribute name="resolution" type="xs:string"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="PhoneSubInfo">
+ <xs:complexType>
+ <xs:attribute name="subscriberId" type="xs:string"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="BuildInfo">
+ <xs:complexType>
+ <xs:attribute name="Xdpi" type="xs:decimal"/>
+ <xs:attribute name="Ydpi" type="xs:decimal"/>
+ <xs:attribute name="androidPlatformVersion" type="xs:integer"/>
+ <xs:attribute name="buildID" type="xs:string"/>
+ <xs:attribute name="buildName" type="xs:string"/>
+ <xs:attribute name="buildVersion" type="xs:string"/>
+ <xs:attribute name="build_board" type="xs:string"/>
+ <xs:attribute name="build_brand" type="xs:string"/>
+ <xs:attribute name="build_device" type="xs:string"/>
+ <xs:attribute name="build_fingerprint" type="xs:string"/>
+ <xs:attribute name="build_model" type="xs:string"/>
+ <xs:attribute name="build_type" type="xs:string"/>
+ <xs:attribute name="deviceID" type="xs:string"/>
+ <xs:attribute name="imei" type="xs:integer"/>
+ <xs:attribute name="imsi" type="xs:integer"/>
+ <xs:attribute name="keypad" type="xs:string"/>
+ <xs:attribute name="locales" type="xs:string"/>
+ <xs:attribute name="navigation" type="xs:string"/>
+ <xs:attribute name="network" type="xs:string"/>
+ <xs:attribute name="touch" type="xs:string"/>
+ <xs:attribute name="openGlEsVersion" type="xs:string"/>
+ <xs:attribute name="build_abi" type="xs:string"/>
+ <xs:attribute name="build_abi2" type="xs:string"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="FeatureInfo" type="featureInfoType"/>
+ <xs:element name="ProcessInfo" type="processInfoType"/>
+ </xs:sequence>
+</xs:complexType>
+
+<xs:complexType name="hostInfoType">
+ <xs:sequence>
+ <xs:element name="Os">
+ <xs:complexType>
+ <xs:attribute name="arch" type="xs:string"/>
+ <xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="version" type="xs:string"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="Java">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="version" type="xs:string"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="Cts">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="IntValue" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string"/>
+ <xs:attribute name="value" type="xs:integer"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="version" type="xs:string"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string"/>
+</xs:complexType>
+
+<xs:complexType name="featureInfoType">
+ <xs:sequence>
+ <xs:element name="Feature" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string" />
+ <xs:attribute name="type" type="xs:string" />
+ <xs:attribute name="available" type="xs:string" />
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+</xs:complexType>
+
+<xs:complexType name="processInfoType">
+ <xs:sequence>
+ <xs:element name="Process" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:string" />
+ <xs:attribute name="uid" type="xs:integer" />
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+</xs:complexType>
+
+<xs:complexType name="summaryType">
+ <xs:attribute name="failed" type="xs:integer"/>
+ <xs:attribute name="notExecuted" type="xs:integer"/>
+ <xs:attribute name="pass" type="xs:integer"/>
+ <xs:attribute name="timeout" type="xs:integer"/>
+ <xs:attribute name="omitted" type="xs:integer"/>
+ <xs:attribute name="total" type="xs:integer"/>
+</xs:complexType>
+
+<xs:complexType name="testPackageType">
+ <xs:complexContent>
+ <xs:extension base="summaryType">
+ <xs:sequence>
+ <xs:element name="TestCase" type="testCaseType" />
+ </xs:sequence>
+ <xs:attribute name="digest" type="xs:hexBinary" />
+ <xs:attribute name="name" type="xs:string" use="required" />
+ <xs:attribute name="runtime" type="xs:string" />
+ </xs:extension>
+ </xs:complexContent>
+</xs:complexType>
+
+<xs:complexType name="testCaseType">
+ <xs:sequence>
+ <xs:element name="Test" type="testType" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="required"/>
+</xs:complexType>
+
+<xs:complexType name="testType">
+ <xs:sequence>
+ <xs:element name="FailedScene" minOccurs="0" maxOccurs="1">
+ <xs:complexType>
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute name="message" type="xs:string" />
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="result" type="resultType" use="required"/>
+</xs:complexType>
+
+<xs:simpleType name="resultType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="pass"/>
+ <xs:enumeration value="fail"/>
+ <xs:enumeration value="timeout"/>
+ <xs:enumeration value="notExecuted"/>
+ <xs:enumeration value="omitted"/>
+ </xs:restriction>
+</xs:simpleType>
+</xs:schema>
diff --git a/tools/tradefed-host/res/result/cts_result.xsl b/tools/tradefed-host/res/result/cts_result.xsl
new file mode 100644
index 0000000..cb220e1
--- /dev/null
+++ b/tools/tradefed-host/res/result/cts_result.xsl
@@ -0,0 +1,513 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp " "> ]>
+<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
+
+ <xsl:template match="/">
+
+ <html>
+ <STYLE type="text/css">
+ @import "cts_result.css";
+ </STYLE>
+
+ <body>
+ <!-- Title of the Report -->
+ <DIV id="title">
+ <TABLE>
+ <TR>
+ <TD width="40%" align="left"><img src="logo.gif"></img></TD>
+ <TD width="60%" align="left">
+ <h1>Test Report for <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@build_model"/> -
+ <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@deviceID"/>
+ </h1>
+ </TD>
+ </TR>
+ </TABLE>
+ </DIV>
+ <img src="newrule-green.png" align="left"></img>
+
+ <br></br>
+ <br></br>
+
+ <!-- Header with phone and plan information -->
+ <DIV id="summary">
+ <TABLE width="90%" frame="none">
+ <TR>
+ <TH>Device Information</TH>
+ <TH>Test Summary</TH>
+ </TR>
+
+ <TR>
+ <TD>
+ <!-- Device information -->
+ <div id="summaryinfo">
+ <TABLE width="75%">
+ <TR>
+ <TD class="rowtitle">Build Model</TD>
+ <TD>
+ <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@build_model"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Build Name</TD>
+ <TD>
+ <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@buildName"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Device ID</TD>
+ <TD>
+ <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@deviceID"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Firmware Version</TD>
+ <TD>
+ <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@buildVersion"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Firmware Build Number</TD>
+ <TD>
+ <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@buildID"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Build Fingerprint</TD>
+ <TD>
+ <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@build_fingerprint"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Build ABI</TD>
+ <TD>
+ <xsl:value-of
+ select="TestResult/DeviceInfo/BuildInfo/@build_abi"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Build ABI2</TD>
+ <TD>
+ <xsl:value-of
+ select="TestResult/DeviceInfo/BuildInfo/@build_abi2"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Android Platform Version</TD>
+ <TD>
+ <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@androidPlatformVersion"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Supported Locales</TD>
+ <TD>
+ <xsl:call-template name="formatDelimitedString">
+ <xsl:with-param name="string" select="TestResult/DeviceInfo/BuildInfo/@locales"/>
+ </xsl:call-template>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Screen size</TD>
+ <TD>
+ <xsl:value-of select="TestResult/DeviceInfo/Screen/@resolution"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Phone number</TD>
+ <TD>
+ <xsl:value-of select="TestResult/DeviceInfo/PhoneSubInfo/@subscriberId"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">x dpi</TD>
+ <TD>
+ <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@Xdpi"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">y dpi</TD>
+ <TD>
+ <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@Ydpi"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Touch</TD>
+ <TD>
+ <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@touch"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Navigation</TD>
+ <TD>
+ <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@navigation"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Keypad</TD>
+ <TD>
+ <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@keypad"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Network</TD>
+ <TD>
+ <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@network"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">IMEI</TD>
+ <TD>
+ <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@imei"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">IMSI</TD>
+ <TD>
+ <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@imsi"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Open GL ES Version</TD>
+ <TD>
+ <xsl:value-of select="TestResult/DeviceInfo/BuildInfo/@openGlEsVersion"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Features</TD>
+ <TD>
+ <xsl:for-each select="TestResult/DeviceInfo/FeatureInfo/Feature[@type='sdk']">
+ <xsl:text>[</xsl:text>
+ <xsl:choose>
+ <xsl:when test="@available = 'true'">
+ <xsl:text>X</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>_</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:text>] </xsl:text>
+
+ <xsl:value-of select="@name" />
+ <br />
+ </xsl:for-each>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Other Features</TD>
+ <TD>
+ <UL>
+ <xsl:for-each select="TestResult/DeviceInfo/FeatureInfo/Feature[@type='other']">
+ <LI><xsl:value-of select="@name" /></LI>
+ </xsl:for-each>
+ </UL>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Root Processes</TD>
+ <TD>
+ <UL>
+ <xsl:for-each select="TestResult/DeviceInfo/ProcessInfo/Process[@uid='0']">
+ <LI><xsl:value-of select="@name" /></LI>
+ </xsl:for-each>
+ </UL>
+ </TD>
+ </TR>
+ </TABLE>
+ </div>
+ </TD>
+
+ <!-- plan information -->
+ <TD>
+ <div id="summaryinfo">
+ <TABLE width="75%">
+ <TR>
+ <TD class="rowtitle">CTS version</TD>
+ <TD>
+ <xsl:value-of select="TestResult/HostInfo/Cts/@version"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Test timeout</TD>
+ <TD>
+ <xsl:value-of select="TestResult/HostInfo/Cts/IntValue[@name='testStatusTimeoutMs']/@value" /> ms
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Host Info</TD>
+ <TD>
+ <xsl:value-of select="TestResult/HostInfo/@name"/>
+ (<xsl:value-of select="TestResult/HostInfo/Os/@name"/> -
+ <xsl:value-of select="TestResult/HostInfo/Os/@version"/>)
+ </TD>
+ </TR>
+ <TR><TD><BR></BR></TD><TD></TD></TR>
+ <TR>
+ <TD class="rowtitle">Plan name</TD>
+ <TD>
+ <xsl:value-of select="TestResult/@testPlan"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Profile</TD>
+ <TD>
+ <xsl:value-of select="TestResult/@profile"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Start time</TD>
+ <TD>
+ <xsl:value-of select="TestResult/@starttime"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">End time</TD>
+ <TD>
+ <xsl:value-of select="TestResult/@endtime"/>
+ </TD>
+ </TR>
+
+ <!-- Test Summary -->
+ <TR><TD><BR></BR></TD><TD></TD></TR>
+ <TR>
+ <TD class="rowtitle">Tests Passed</TD>
+ <TD>
+ <xsl:value-of select="TestResult/Summary/@pass"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Tests Failed</TD>
+ <TD>
+ <xsl:value-of select="TestResult/Summary/@failed"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Tests Timed out</TD>
+ <TD>
+ <xsl:value-of select="TestResult/Summary/@timeout"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Tests Omitted</TD>
+ <TD>
+ <xsl:value-of select="TestResult/Summary/@omitted"/>
+ </TD>
+ </TR>
+ <TR>
+ <TD class="rowtitle">Tests Not Executed</TD>
+ <TD>
+ <xsl:value-of select="TestResult/Summary/@notExecuted"/>
+ </TD>
+ </TR>
+ </TABLE>
+ </div>
+ </TD>
+ </TR>
+ </TABLE>
+ </DIV>
+
+ <!-- High level summary of test execution -->
+ <h2 align="center">Test Summary by Package</h2>
+ <DIV id="testsummary">
+ <TABLE>
+ <TR>
+ <TH>Test Package</TH>
+ <TH>Passed</TH>
+ <TH>Failed</TH>
+ <TH>Timed Out</TH>
+ <TH>Total Tests</TH>
+ </TR>
+ <xsl:for-each select="TestResult/TestPackage">
+ <TR>
+ <TD>
+ <xsl:variable name="href"><xsl:value-of select="@name"/></xsl:variable>
+ <a href="#{$href}"><xsl:value-of select="@name"/></a>
+ </TD>
+ <TD>
+ <xsl:value-of select="@pass"/>
+ </TD>
+ <TD>
+ <xsl:value-of select="@failed"/>
+ </TD>
+ <TD>
+ <xsl:value-of select="@timeout"/>
+ </TD>
+ <TD>
+ <xsl:value-of select="@total"/>
+ </TD>
+ </TR>
+ </xsl:for-each> <!-- end package -->
+ </TABLE>
+ </DIV>
+
+ <!-- Details of all the executed tests -->
+ <h2 align="center">Detailed Test Report</h2>
+
+ <!-- test package -->
+ <DIV id="testdetail">
+ <xsl:for-each select="TestResult/TestPackage">
+ <DIV id="none">
+ <TABLE>
+ <TR>
+ <TD class="none" align="left">
+ <xsl:variable name="href"><xsl:value-of select="@name"/></xsl:variable>
+ <a name="{$href}">Compatibility Test Package: <xsl:value-of select="@name"/></a>
+ </TD>
+ </TR>
+ </TABLE>
+ </DIV>
+
+ <TABLE>
+ <TR>
+ <TH width="25%">Test</TH>
+ <TH width="7%">Result</TH>
+ <TH width="68%">Failure Details</TH>
+ </TR>
+
+ <!-- test case -->
+ <xsl:for-each select="TestCase">
+
+ <!-- emit a blank row before every test suite name -->
+ <xsl:if test="position()!=1">
+ <TR> <TD class="testcasespacer" colspan="3"></TD> </TR>
+ </xsl:if>
+
+
+ <TR>
+ <TD class="testcase" colspan="3">
+ <xsl:value-of select="@name"/>
+ </TD>
+ </TR>
+
+ <!-- test -->
+ <xsl:for-each select="Test">
+ <TR>
+ <TD class="testname"> -- <xsl:value-of select="@name"/></TD>
+
+ <!-- test results -->
+ <xsl:choose>
+ <xsl:when test="string(@KnownFailure)">
+ <!-- "pass" indicates the that test actually passed (results have been inverted already) -->
+ <xsl:if test="@result='pass'">
+ <TD class="pass">
+ <div style="text-align: center; margin-left:auto; margin-right:auto;">
+ known problem
+ </div>
+ </TD>
+ <TD class="failuredetails"></TD>
+ </xsl:if>
+
+ <!-- "fail" indicates that a known failure actually passed (results have been inverted already) -->
+ <xsl:if test="@result='fail'">
+ <TD class="failed">
+ <div style="text-align: center; margin-left:auto; margin-right:auto;">
+ <xsl:value-of select="@result"/>
+ </div>
+ </TD>
+ <TD class="failuredetails">
+ <div id="details">
+ A test that was a known failure actually passed. Please check.
+ </div>
+ </TD>
+ </xsl:if>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <xsl:if test="@result='pass'">
+ <TD class="pass">
+ <div style="text-align: center; margin-left:auto; margin-right:auto;">
+ <xsl:value-of select="@result"/>
+ </div>
+ </TD>
+ <TD class="failuredetails"></TD>
+ </xsl:if>
+
+ <xsl:if test="@result='fail'">
+ <TD class="failed">
+ <div style="text-align: center; margin-left:auto; margin-right:auto;">
+ <xsl:value-of select="@result"/>
+ </div>
+ </TD>
+ <TD class="failuredetails">
+ <div id="details">
+ <xsl:value-of select="FailedScene/@message"/>
+ </div>
+ </TD>
+ </xsl:if>
+
+ <xsl:if test="@result='timeout'">
+ <TD class="timeout">
+ <div style="text-align: center; margin-left:auto; margin-right:auto;">
+ <xsl:value-of select="@result"/>
+ </div>
+ <TD class="failuredetails"></TD>
+ </TD>
+ </xsl:if>
+
+ <xsl:if test="@result='omitted'">
+ <TD class="omitted">
+ <div style="text-align: center; margin-left:auto; margin-right:auto;">
+ <xsl:value-of select="@result"/>
+ </div>
+ </TD>
+ <TD class="failuredetails"></TD>
+ </xsl:if>
+
+ <xsl:if test="@result='notExecuted'">
+ <TD class="notExecuted">
+ <div style="text-align: center; margin-left:auto; margin-right:auto;">
+ <xsl:value-of select="@result"/>
+ </div>
+ </TD>
+ <TD class="failuredetails"></TD>
+ </xsl:if>
+ </xsl:otherwise>
+ </xsl:choose>
+ </TR> <!-- finished with a row -->
+ </xsl:for-each> <!-- end test -->
+ </xsl:for-each> <!-- end test case -->
+ </TABLE>
+ </xsl:for-each> <!-- end test package -->
+ </DIV>
+ </body>
+ </html>
+ </xsl:template>
+
+ <!-- Take a delimited string and insert line breaks after a some number of elements. -->
+ <xsl:template name="formatDelimitedString">
+ <xsl:param name="string" />
+ <xsl:param name="numTokensPerRow" select="10" />
+ <xsl:param name="tokenIndex" select="1" />
+ <xsl:if test="$string">
+ <!-- Requires the last element to also have a delimiter after it. -->
+ <xsl:variable name="token" select="substring-before($string, ';')" />
+ <xsl:value-of select="$token" />
+ <xsl:text> </xsl:text>
+
+ <xsl:if test="$tokenIndex mod $numTokensPerRow = 0">
+ <br />
+ </xsl:if>
+
+ <xsl:call-template name="formatDelimitedString">
+ <xsl:with-param name="string" select="substring-after($string, ';')" />
+ <xsl:with-param name="numTokensPerRow" select="$numTokensPerRow" />
+ <xsl:with-param name="tokenIndex" select="$tokenIndex + 1" />
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/tools/tradefed-host/res/result/logo.gif b/tools/tradefed-host/res/result/logo.gif
new file mode 100644
index 0000000..61970b3
--- /dev/null
+++ b/tools/tradefed-host/res/result/logo.gif
Binary files differ
diff --git a/tools/tradefed-host/res/result/newrule-green.png b/tools/tradefed-host/res/result/newrule-green.png
new file mode 100644
index 0000000..10a4194
--- /dev/null
+++ b/tools/tradefed-host/res/result/newrule-green.png
Binary files differ
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/device/DeviceInfoCollector.java b/tools/tradefed-host/src/com/android/cts/tradefed/device/DeviceInfoCollector.java
new file mode 100644
index 0000000..b914f2e
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/device/DeviceInfoCollector.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2010 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.device;
+
+import com.android.ddmlib.Log;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.testtype.InstrumentationTest;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * Collects info from device under test.
+ * <p/>
+ * This class simply serves as a conduit for grabbing info from device using the device info
+ * collector apk, and forwarding that data directly to the {@link ITestInvocationListener} as run
+ * metrics.
+ */
+public class DeviceInfoCollector {
+
+ private static final String LOG_TAG = "DeviceInfoCollector";
+ private static final String APK_NAME = "TestDeviceSetup";
+ public static final String APP_PACKAGE_NAME = "android.tests.devicesetup";
+ private static final String INSTRUMENTATION_NAME = "android.tests.getinfo.DeviceInfoInstrument";
+ // metric constants
+ // this values must exactly match those defined in
+ // cts/tools/device-setup/.../DeviceInfoInstrument.java
+ public static final String SCREEN_WIDTH = "screen_width";
+ public static final String SCREEN_HEIGHT = "screen_height";
+ public static final String PHONE_NUMBER = "phoneNumber";
+ public static final String FEATURES = "features";
+ public static final String PROCESSES = "processes";
+
+ /**
+ * Installs and runs the device info collector instrumentation, and forwards results
+ * to the <var>listeners</var>
+ *
+ * @param device
+ * @param listeners
+ * @throws DeviceNotAvailableException
+ */
+ public static void collectDeviceInfo(ITestDevice device, File testApkDir,
+ List<ITestInvocationListener> listeners) throws DeviceNotAvailableException {
+ File apkFile = new File(testApkDir, String.format("%s.apk", APK_NAME));
+ if (!apkFile.exists()) {
+ Log.e(LOG_TAG, String.format("Could not find %s", apkFile.getAbsolutePath()));
+ }
+ // collect the instrumentation bundle results using instrumentation test
+ // should work even though no tests will actually be run
+ InstrumentationTest instrTest = new InstrumentationTest();
+ instrTest.setDevice(device);
+ instrTest.setInstallFile(apkFile);
+ // no need to collect tests and re-run
+ instrTest.setRerunMode(false);
+ instrTest.setPackageName(APP_PACKAGE_NAME);
+ instrTest.setRunnerName(INSTRUMENTATION_NAME);
+ instrTest.run(listeners);
+ }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
new file mode 100644
index 0000000..4c29b01
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
@@ -0,0 +1,635 @@
+/*
+ * Copyright (C) 2010 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.result;
+
+import com.android.cts.tradefed.device.DeviceInfoCollector;
+import com.android.cts.tradefed.targetsetup.CtsBuildHelper;
+import com.android.ddmlib.Log;
+import com.android.ddmlib.Log.LogLevel;
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.result.CollectingTestListener;
+import com.android.tradefed.result.LogDataType;
+import com.android.tradefed.result.TestResult;
+import com.android.tradefed.result.TestRunResult;
+import com.android.tradefed.result.TestResult.TestStatus;
+import com.android.tradefed.targetsetup.IBuildInfo;
+import com.android.tradefed.targetsetup.IFolderBuildInfo;
+import com.android.tradefed.util.FileUtil;
+
+import org.kxml2.io.KXmlSerializer;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Writes results to an XML files in the CTS format.
+ * <p/>
+ * Collects all test info in memory, then dumps to file when invocation is complete.
+ * <p/>
+ * Outputs xml in format governed by the cts_result.xsd
+ */
+public class CtsXmlResultReporter extends CollectingTestListener {
+
+ private static final String LOG_TAG = "CtsXmlResultReporter";
+
+ private static final String TEST_RESULT_FILE_NAME = "testResult.xml";
+ private static final String CTS_RESULT_FILE_VERSION = "2.0";
+ private static final String CTS_VERSION = "99";
+
+
+ private static final String[] CTS_RESULT_RESOURCES = {"cts_result.xsl", "cts_result.css",
+ "logo.gif", "newrule-green.png"};
+
+ /** the XML namespace */
+ private static final String ns = null;
+
+ private static final String REPORT_DIR_NAME = "output-file-path";
+ @Option(name=REPORT_DIR_NAME, description="root file system path to directory to store xml " +
+ "test results and associated logs. If not specified, results will be stored at " +
+ "<cts root>/repository/results")
+ protected File mReportDir = null;
+
+ protected IBuildInfo mBuildInfo;
+
+ private String mStartTime;
+
+ public void setReportDir(File reportDir) {
+ mReportDir = reportDir;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void invocationStarted(IBuildInfo buildInfo) {
+ super.invocationStarted(buildInfo);
+ if (mReportDir == null) {
+ if (!(buildInfo instanceof IFolderBuildInfo)) {
+ throw new IllegalArgumentException("build info is not a IFolderBuildInfo");
+ }
+ IFolderBuildInfo ctsBuild = (IFolderBuildInfo)buildInfo;
+ try {
+ CtsBuildHelper buildHelper = new CtsBuildHelper(ctsBuild.getRootDir());
+ mReportDir = buildHelper.getResultsDir();
+
+ } catch (FileNotFoundException e) {
+ throw new IllegalArgumentException("unrecognized cts structure", e);
+ }
+ }
+ // create a unique directory for saving results, using old cts host convention
+ // TODO: in future, consider using LogFileSaver to create build-specific directories
+ mReportDir = new File(mReportDir, getResultTimestamp());
+ mReportDir.mkdirs();
+ mStartTime = getTimestamp();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void testLog(String dataName, LogDataType dataType, InputStream dataStream) {
+ // TODO: implement this
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void testFailed(TestFailure status, TestIdentifier test, String trace) {
+ super.testFailed(status, test, trace);
+ Log.i(LOG_TAG, String.format("Test %s#%s: %s\n%s", test.getClassName(), test.getTestName(),
+ status.toString(), trace));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void testRunEnded(long elapsedTime, Map<String, String> runMetrics) {
+ super.testRunEnded(elapsedTime, runMetrics);
+ Log.i(LOG_TAG, String.format("Test run %s complete. Tests passed %d, failed %d, error %d",
+ getCurrentRunResults().getName(), getCurrentRunResults().getNumPassedTests(),
+ getCurrentRunResults().getNumFailedTests(),
+ getCurrentRunResults().getNumErrorTests()));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void invocationEnded(long elapsedTime) {
+ super.invocationEnded(elapsedTime);
+ createXmlResult(mReportDir, mStartTime, elapsedTime);
+ copyFormattingFiles(mReportDir);
+ zipResults(mReportDir);
+ }
+
+ /**
+ * Creates a report file and populates it with the report data from the completed tests.
+ */
+ private void createXmlResult(File reportDir, String startTimestamp, long elapsedTime) {
+ String endTime = getTimestamp();
+
+ OutputStream stream = null;
+ try {
+ stream = createOutputResultStream(reportDir);
+ KXmlSerializer serializer = new KXmlSerializer();
+ serializer.setOutput(stream, "UTF-8");
+ serializer.startDocument("UTF-8", false);
+ serializer.setFeature(
+ "http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ serializer.processingInstruction("xml-stylesheet type=\"text/xsl\" " +
+ "href=\"cts_result.xsl\"");
+ serializeResultsDoc(serializer, startTimestamp, endTime);
+ serializer.endDocument();
+ // TODO: output not executed timeout omitted counts
+ String msg = String.format("XML test result file generated at %s. Total tests %d, " +
+ "Failed %d, Error %d", reportDir.getAbsolutePath(), getNumTotalTests(),
+ getNumFailedTests(), getNumErrorTests());
+ Log.logAndDisplay(LogLevel.INFO, LOG_TAG, msg);
+ Log.logAndDisplay(LogLevel.INFO, LOG_TAG, String.format("Time: %s",
+ formatElapsedTime(elapsedTime)));
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "Failed to generate report data");
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (IOException ignored) {
+ }
+ }
+ }
+ }
+
+ /**
+ * Output the results XML.
+ *
+ * @param serializer the {@link KXmlSerializer} to use
+ * @param startTime the user-friendly starting time of the test invocation
+ * @param endTime the user-friendly ending time of the test invocation
+ * @throws IOException
+ */
+ private void serializeResultsDoc(KXmlSerializer serializer, String startTime, String endTime)
+ throws IOException {
+ serializer.startTag(ns, "TestResult");
+ // TODO: output test plan and profile values
+ serializer.attribute(ns, "testPlan", "unknown");
+ serializer.attribute(ns, "profile", "unknown");
+ serializer.attribute(ns, "starttime", startTime);
+ serializer.attribute(ns, "endtime", endTime);
+ serializer.attribute(ns, "version", CTS_RESULT_FILE_VERSION);
+
+ serializeDeviceInfo(serializer);
+ serializeHostInfo(serializer);
+ serializeTestSummary(serializer);
+ serializeTestResults(serializer);
+ }
+
+ /**
+ * Output the device info XML.
+ *
+ * @param serializer
+ */
+ private void serializeDeviceInfo(KXmlSerializer serializer) throws IOException {
+ serializer.startTag(ns, "DeviceInfo");
+
+ TestRunResult deviceInfoResult = findRunResult(DeviceInfoCollector.APP_PACKAGE_NAME);
+ if (deviceInfoResult == null) {
+ Log.w(LOG_TAG, String.format("Could not find device info run %s",
+ DeviceInfoCollector.APP_PACKAGE_NAME));
+ return;
+ }
+ // Extract metrics that need extra handling, and then dump the remainder into BuildInfo
+ Map<String, String> metricsCopy = new HashMap<String, String>(
+ deviceInfoResult.getRunMetrics());
+ serializer.startTag(ns, "Screen");
+ String screenWidth = metricsCopy.remove(DeviceInfoCollector.SCREEN_WIDTH);
+ String screenHeight = metricsCopy.remove(DeviceInfoCollector.SCREEN_HEIGHT);
+ serializer.attribute(ns, "resolution", String.format("%sx%s", screenWidth, screenHeight));
+ serializer.endTag(ns, "Screen");
+
+ serializer.startTag(ns, "PhoneSubInfo");
+ serializer.attribute(ns, "subscriberId", metricsCopy.remove(
+ DeviceInfoCollector.PHONE_NUMBER));
+ serializer.endTag(ns, "PhoneSubInfo");
+
+ String featureData = metricsCopy.remove(DeviceInfoCollector.FEATURES);
+ String processData = metricsCopy.remove(DeviceInfoCollector.PROCESSES);
+
+ // dump the remaining metrics without translation
+ serializer.startTag(ns, "BuildInfo");
+ for (Map.Entry<String, String> metricEntry : metricsCopy.entrySet()) {
+ serializer.attribute(ns, metricEntry.getKey(), metricEntry.getValue());
+ }
+ serializer.endTag(ns, "BuildInfo");
+
+ serializeFeatureInfo(serializer, featureData);
+ serializeProcessInfo(serializer, processData);
+
+ serializer.endTag(ns, "DeviceInfo");
+ }
+
+ /**
+ * Prints XML indicating what features are supported by the device. It parses a string from the
+ * featureData argument that is in the form of "feature1:true;feature2:false;featuer3;true;"
+ * with a trailing semi-colon.
+ *
+ * <pre>
+ * <FeatureInfo>
+ * <Feature name="android.name.of.feature" available="true" />
+ * ...
+ * </FeatureInfo>
+ * </pre>
+ *
+ * @param serializer used to create XML
+ * @param featureData raw unparsed feature data
+ */
+ private void serializeFeatureInfo(KXmlSerializer serializer, String featureData) throws IOException {
+ serializer.startTag(ns, "FeatureInfo");
+
+ if (featureData == null) {
+ featureData = "";
+ }
+
+ String[] featurePairs = featureData.split(";");
+ for (String featurePair : featurePairs) {
+ String[] nameTypeAvailability = featurePair.split(":");
+ if (nameTypeAvailability.length >= 3) {
+ serializer.startTag(ns, "Feature");
+ serializer.attribute(ns, "name", nameTypeAvailability[0]);
+ serializer.attribute(ns, "type", nameTypeAvailability[1]);
+ serializer.attribute(ns, "available", nameTypeAvailability[2]);
+ serializer.endTag(ns, "Feature");
+ }
+ }
+ serializer.endTag(ns, "FeatureInfo");
+ }
+
+ /**
+ * Prints XML data indicating what particular processes of interest were running on the device.
+ * It parses a string from the rootProcesses argument that is in the form of
+ * "processName1;processName2;..." with a trailing semi-colon.
+ *
+ * <pre>
+ * <ProcessInfo>
+ * <Process name="long_cat_viewer" uid="0" />
+ * ...
+ * </ProcessInfo>
+ * </pre>
+ *
+ * @param document
+ * @param parentNode
+ * @param deviceInfo
+ */
+ private void serializeProcessInfo(KXmlSerializer serializer, String rootProcesses)
+ throws IOException {
+ serializer.startTag(ns, "ProcessInfo");
+
+ if (rootProcesses == null) {
+ rootProcesses = "";
+ }
+
+ String[] processNames = rootProcesses.split(";");
+ for (String processName : processNames) {
+ processName = processName.trim();
+ if (processName.length() > 0) {
+ serializer.startTag(ns, "Process");
+ serializer.attribute(ns, "name", processName);
+ serializer.attribute(ns, "uid", "0");
+ serializer.endTag(ns, "Process");
+ }
+ }
+ serializer.endTag(ns, "ProcessInfo");
+ }
+
+ /**
+ * Finds the {@link TestRunResult} with the given name.
+ *
+ * @param runName
+ * @return the {@link TestRunResult}
+ */
+ private TestRunResult findRunResult(String runName) {
+ for (TestRunResult runResult : getRunResults()) {
+ if (runResult.getName().equals(runName)) {
+ return runResult;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Output the host info XML.
+ *
+ * @param serializer
+ */
+ private void serializeHostInfo(KXmlSerializer serializer) throws IOException {
+ serializer.startTag(ns, "HostInfo");
+
+ String hostName = "";
+ try {
+ hostName = InetAddress.getLocalHost().getHostName();
+ } catch (UnknownHostException ignored) {}
+ serializer.attribute(ns, "name", hostName);
+
+ serializer.startTag(ns, "Os");
+ serializer.attribute(ns, "name", System.getProperty("os.name"));
+ serializer.attribute(ns, "version", System.getProperty("os.version"));
+ serializer.attribute(ns, "arch", System.getProperty("os.arch"));
+ serializer.endTag(ns, "Os");
+
+ serializer.startTag(ns, "Java");
+ serializer.attribute(ns, "name", System.getProperty("java.vendor"));
+ serializer.attribute(ns, "version", System.getProperty("java.version"));
+ serializer.endTag(ns, "Java");
+
+ serializer.startTag(ns, "Cts");
+ serializer.attribute(ns, "version", CTS_VERSION);
+ // TODO: consider outputting tradefed options here
+ serializer.endTag(ns, "Cts");
+
+ serializer.endTag(ns, "HostInfo");
+ }
+
+ /**
+ * Output the test summary XML containing summary totals for all tests.
+ *
+ * @param serializer
+ * @throws IOException
+ */
+ private void serializeTestSummary(KXmlSerializer serializer) throws IOException {
+ serializer.startTag(ns, "Summary");
+ serializer.attribute(ns, "failed", Integer.toString(getNumErrorTests() +
+ getNumFailedTests()));
+ // TODO: output notExecuted, timeout, and omitted count
+ serializer.attribute(ns, "notExecuted", "0");
+ serializer.attribute(ns, "timeout", "0");
+ serializer.attribute(ns, "omitted", "0");
+ serializer.attribute(ns, "pass", Integer.toString(getNumPassedTests()));
+ serializer.attribute(ns, "total", Integer.toString(getNumTotalTests()));
+ serializer.endTag(ns, "Summary");
+ }
+
+ /**
+ * Output the detailed test results XML.
+ *
+ * @param serializer
+ * @throws IOException
+ */
+ private void serializeTestResults(KXmlSerializer serializer) throws IOException {
+ for (TestRunResult runResult : getRunResults()) {
+ serializeTestRunResult(serializer, runResult);
+ }
+ }
+
+ /**
+ * Output the XML for one test run aka test package.
+ *
+ * @param serializer
+ * @param runResult the {@link TestRunResult}
+ * @throws IOException
+ */
+ private void serializeTestRunResult(KXmlSerializer serializer, TestRunResult runResult)
+ throws IOException {
+ if (runResult.getName().equals(DeviceInfoCollector.APP_PACKAGE_NAME)) {
+ // ignore run results for the info collecting packages
+ return;
+ }
+ serializer.startTag(ns, "TestPackage");
+ serializer.attribute(ns, "name", runResult.getName());
+ serializer.attribute(ns, "runTime", formatElapsedTime(runResult.getElapsedTime()));
+ // TODO: generate digest
+ serializer.attribute(ns, "digest", "");
+ serializer.attribute(ns, "failed", Integer.toString(runResult.getNumErrorTests() +
+ runResult.getNumFailedTests()));
+ // TODO: output notExecuted, timeout, and omitted count
+ serializer.attribute(ns, "notExecuted", "0");
+ serializer.attribute(ns, "timeout", "0");
+ serializer.attribute(ns, "omitted", "0");
+ serializer.attribute(ns, "pass", Integer.toString(runResult.getNumPassedTests()));
+ serializer.attribute(ns, "total", Integer.toString(runResult.getNumTests()));
+
+ // the results XML needs to organize test's by class. Build a nested data structure that
+ // group's the results by class name
+ Map<String, Map<TestIdentifier, TestResult>> classResultsMap = buildClassNameMap(
+ runResult.getTestResults());
+
+ for (Map.Entry<String, Map<TestIdentifier, TestResult>> resultsEntry :
+ classResultsMap.entrySet()) {
+ serializer.startTag(ns, "TestCase");
+ serializer.attribute(ns, "name", resultsEntry.getKey());
+ serializeTests(serializer, resultsEntry.getValue());
+ serializer.endTag(ns, "TestCase");
+ }
+ serializer.endTag(ns, "TestPackage");
+ }
+
+ /**
+ * Organizes the test run results into a format organized by class name.
+ */
+ private Map<String, Map<TestIdentifier, TestResult>> buildClassNameMap(
+ Map<TestIdentifier, TestResult> results) {
+ // use a linked hashmap to have predictable iteration order
+ Map<String, Map<TestIdentifier, TestResult>> classResultMap =
+ new LinkedHashMap<String, Map<TestIdentifier, TestResult>>();
+ for (Map.Entry<TestIdentifier, TestResult> resultEntry : results.entrySet()) {
+ String className = resultEntry.getKey().getClassName();
+ Map<TestIdentifier, TestResult> resultsForClass = classResultMap.get(className);
+ if (resultsForClass == null) {
+ resultsForClass = new LinkedHashMap<TestIdentifier, TestResult>();
+ classResultMap.put(className, resultsForClass);
+ }
+ resultsForClass.put(resultEntry.getKey(), resultEntry.getValue());
+ }
+ return classResultMap;
+ }
+
+ /**
+ * Output XML for given map of tests their results
+ *
+ * @param serializer
+ * @param results
+ * @throws IOException
+ */
+ private void serializeTests(KXmlSerializer serializer, Map<TestIdentifier, TestResult> results)
+ throws IOException {
+ for (Map.Entry<TestIdentifier, TestResult> resultEntry : results.entrySet()) {
+ serializeTest(serializer, resultEntry.getKey(), resultEntry.getValue());
+ }
+ }
+
+ /**
+ * Output the XML for given test and result.
+ *
+ * @param serializer
+ * @param testId
+ * @param result
+ * @throws IOException
+ */
+ private void serializeTest(KXmlSerializer serializer, TestIdentifier testId, TestResult result)
+ throws IOException {
+ serializer.startTag(ns, "Test");
+ serializer.attribute(ns, "name", testId.getTestName());
+ serializer.attribute(ns, "result", convertStatus(result.getStatus()));
+
+ if (result.getStackTrace() != null) {
+ String sanitizedStack = sanitizeStackTrace(result.getStackTrace());
+ serializer.startTag(ns, "FailedScene");
+ serializer.attribute(ns, "message", getFailureMessageFromStackTrace(sanitizedStack));
+ serializer.text(sanitizedStack);
+ serializer.endTag(ns, "FailedScene");
+ }
+ serializer.endTag(ns, "Test");
+ }
+
+ /**
+ * Convert a {@link TestStatus} to the result text to output in XML
+ *
+ * @param status the {@link TestStatus}
+ * @return
+ */
+ private String convertStatus(TestStatus status) {
+ switch (status) {
+ case ERROR:
+ return "fail";
+ case FAILURE:
+ return "fail";
+ case PASSED:
+ return "pass";
+ // TODO add notExecuted, omitted timeout
+ }
+ return "omitted";
+ }
+
+ /**
+ * Strip out any invalid XML characters that might cause the report to be unviewable.
+ * http://www.w3.org/TR/REC-xml/#dt-character
+ */
+ private static String sanitizeStackTrace(String trace) {
+ if (trace != null) {
+ return trace.replaceAll("[^\\u0009\\u000A\\u000D\\u0020-\\uD7FF\\uE000-\\uFFFD]", "");
+ } else {
+ return null;
+ }
+ }
+
+ private static String getFailureMessageFromStackTrace(String stack) {
+ // This is probably too simplistic to work in all cases, but for now, just return first
+ // line of stack as failure message
+ int firstNewLine = stack.indexOf('\n');
+ if (firstNewLine != -1) {
+ return stack.substring(0, firstNewLine);
+ }
+ return stack;
+ }
+
+ /**
+ * Return the current timestamp as a {@link String} suitable for displaying.
+ * <p/>
+ * Example: Fri Aug 20 15:13:03 PDT 2010
+ */
+ String getTimestamp() {
+ SimpleDateFormat dateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
+ return dateFormat.format(new Date());
+ }
+
+ /**
+ * Return the current timestamp in a compressed format, used to uniquely identify results.
+ * <p/>
+ * Example: 2010.08.16_11.42.12
+ */
+ private String getResultTimestamp() {
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd_HH.mm.ss");
+ return dateFormat.format(new Date());
+ }
+
+ /**
+ * Return a prettified version of the given elapsed time
+ * @return
+ */
+ private String formatElapsedTime(long elapsedTimeMs) {
+ long seconds = TimeUnit.MILLISECONDS.toSeconds(elapsedTimeMs) % 60;
+ long minutes = TimeUnit.MILLISECONDS.toMinutes(elapsedTimeMs) % 60;
+ long hours = TimeUnit.MILLISECONDS.toHours(elapsedTimeMs);
+ StringBuilder time = new StringBuilder();
+ if (hours > 0) {
+ time.append(hours);
+ time.append("h ");
+ }
+ if (minutes > 0) {
+ time.append(minutes);
+ time.append("m ");
+ }
+ time.append(seconds);
+ time.append("s");
+
+ return time.toString();
+ }
+
+ /**
+ * Creates the output stream to use for test results. Exposed for mocking.
+ */
+ OutputStream createOutputResultStream(File reportDir) throws IOException {
+ File reportFile = new File(reportDir, TEST_RESULT_FILE_NAME);
+ Log.i(LOG_TAG, String.format("Created xml report file at %s",
+ reportFile.getAbsolutePath()));
+ return new FileOutputStream(reportFile);
+ }
+
+ /**
+ * Copy the xml formatting files stored in this jar to the results directory
+ *
+ * @param resultsDir
+ */
+ private void copyFormattingFiles(File resultsDir) {
+ for (String resultFileName : CTS_RESULT_RESOURCES) {
+ InputStream configStream = getClass().getResourceAsStream(
+ String.format("/result/%s", resultFileName));
+ if (configStream != null) {
+ File resultFile = new File(resultsDir, resultFileName);
+ try {
+ FileUtil.writeToFile(configStream, resultFile);
+ } catch (IOException e) {
+ Log.w(LOG_TAG, String.format("Failed to write %s to file", resultFileName));
+ }
+ } else {
+ Log.w(LOG_TAG, String.format("Failed to load %s from jar", resultFileName));
+ }
+ }
+ }
+
+ /**
+ * Zip the contents of the given results directory.
+ *
+ * @param resultsDir
+ */
+ private void zipResults(File resultsDir) {
+ // TODO: implement this
+ }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/targetsetup/CtsBuildHelper.java b/tools/tradefed-host/src/com/android/cts/tradefed/targetsetup/CtsBuildHelper.java
new file mode 100644
index 0000000..9597109
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/targetsetup/CtsBuildHelper.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2010 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.targetsetup;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/**
+ * Helper class for retrieving files from the CTS install.
+ * <p/>
+ * Encapsulates the filesystem layout of the CTS installation.
+ */
+public class CtsBuildHelper {
+
+ static final String CTS_DIR_NAME = "android-cts";
+ /** The root location of the extracted CTS package */
+ private final File mRootDir;
+ /** the {@link CTS_DIR_NAME} directory */
+ private final File mCtsDir;
+
+ /**
+ * Creates a {@link CtsBuildHelper}.
+ *
+ * @param rootDir the parent folder that contains the "android-cts" directory and all its
+ * contents.
+ * @throws FileNotFoundException if file does not exist
+ */
+ public CtsBuildHelper(File rootDir) throws FileNotFoundException {
+ mRootDir = rootDir;
+ mCtsDir = new File(mRootDir, CTS_DIR_NAME);
+ if (!mCtsDir.exists()) {
+ throw new FileNotFoundException(String.format(
+ "CTS install folder %s does not exist", mCtsDir.getAbsolutePath()));
+ }
+ }
+
+ /**
+ * @return a {@link File} representing the parent folder of the CTS installation
+ */
+ public File getRootDir() {
+ return mRootDir;
+ }
+
+ /**
+ * @return a {@link File} representing the "android-cts" folder of the CTS installation
+ */
+ public File getCtsDir() {
+ return mCtsDir;
+ }
+
+ /**
+ * @return a {@link File} representing the test application file with given name
+ * @throws FileNotFoundException if file does not exist
+ */
+ public File getTestApp(String appFileName) throws FileNotFoundException {
+ File apkFile = new File(getTestCasesDir(), appFileName);
+ if (!apkFile.exists()) {
+ throw new FileNotFoundException(String.format("CTS test app file %s does not exist",
+ apkFile.getAbsolutePath()));
+ }
+ return apkFile;
+ }
+
+ private File getRepositoryDir() {
+ return new File(getCtsDir(), "repository");
+ }
+
+ /**
+ * @return a {@link File} representing the results directory.
+ */
+ public File getResultsDir() {
+ return new File(getRepositoryDir(), "results");
+ }
+
+ /**
+ * @return a {@link File} representing the test cases directory
+ * @throws FileNotFoundException if dir does not exist
+ */
+ public File getTestCasesDir() throws FileNotFoundException {
+ File dir = new File(getRepositoryDir(), "testcases");
+ if (!dir.exists()) {
+ throw new FileNotFoundException(String.format(
+ "CTS test cases directory %s does not exist", dir.getAbsolutePath()));
+ }
+ return dir;
+ }
+
+ /**
+ * @return a {@link File} representing the test plan directory
+ * @throws FileNotFoundException if dir does not exist
+ */
+ public File getTestPlansDir() throws FileNotFoundException {
+ File dir = new File(getRepositoryDir(), "plans");
+ if (!dir.exists()) {
+ throw new FileNotFoundException(String.format(
+ "CTS test plans directory %s does not exist", dir.getAbsolutePath()));
+ }
+ return dir;
+ }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/targetsetup/CtsBuildProvider.java b/tools/tradefed-host/src/com/android/cts/tradefed/targetsetup/CtsBuildProvider.java
new file mode 100644
index 0000000..90fb8ba
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/targetsetup/CtsBuildProvider.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2010 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.targetsetup;
+
+import com.android.tradefed.config.Option;
+import com.android.tradefed.targetsetup.FolderBuildInfo;
+import com.android.tradefed.targetsetup.IBuildInfo;
+import com.android.tradefed.targetsetup.IBuildProvider;
+import com.android.tradefed.targetsetup.IFolderBuildInfo;
+import com.android.tradefed.targetsetup.TargetSetupError;
+
+import java.io.File;
+
+/**
+ * A simple {@link IBuildProvider} that uses a pre-existing CTS install.
+ */
+public class CtsBuildProvider implements IBuildProvider {
+
+ @Option(name="cts-install-path", description="the path to the cts installation to use")
+ private File mCtsRootDir;
+
+ /**
+ * {@inheritDoc}
+ */
+ public IBuildInfo getBuild() throws TargetSetupError {
+ if (mCtsRootDir == null) {
+ throw new IllegalArgumentException("Missing --cts-install-path");
+ }
+ IFolderBuildInfo ctsBuild = new FolderBuildInfo(0, "cts", "cts");
+ ctsBuild.setRootDir(mCtsRootDir);
+ return ctsBuild;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void buildNotTested(IBuildInfo info) {
+ // ignore
+ }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/targetsetup/CtsRootDeviceSetup.java b/tools/tradefed-host/src/com/android/cts/tradefed/targetsetup/CtsRootDeviceSetup.java
new file mode 100644
index 0000000..589bed3
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/targetsetup/CtsRootDeviceSetup.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2010 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.targetsetup;
+
+import com.android.ddmlib.Log;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.targetsetup.BuildError;
+import com.android.tradefed.targetsetup.DeviceSetup;
+import com.android.tradefed.targetsetup.IBuildInfo;
+import com.android.tradefed.targetsetup.IFolderBuildInfo;
+import com.android.tradefed.targetsetup.ITargetPreparer;
+import com.android.tradefed.targetsetup.TargetSetupError;
+
+import java.io.FileNotFoundException;
+
+/**
+ * A {@link ITargetPreparer} that attempts to automatically perform the CTS-specific manual steps
+ * for setting up a device for CTS testing.
+ * <p/>
+ * This class is NOT intended for 'official' CTS runs against a production device as the steps
+ * performed by this class require a debug build (aka 'adb root' must succeed).
+ * <p/>
+ * This class currently performs the 'Allow mock locations' and 'accessibililty setup' steps
+ * documented in the CTS user manual. It is intended to be used in conjunction with
+ * a {@link DeviceSetup} which will enable the 'Stay Awake' setting and verify that external
+ * storage is present.
+ */
+public class CtsRootDeviceSetup implements ITargetPreparer {
+
+ private static final String LOG_TAG = "CtsRootDeviceSetup";
+
+ // TODO: read this from a configuration file rather than hard-coding
+ private static final String ACCESSIBILITY_SERVICE_APK_FILE_NAME =
+ "CtsDelegatingAccessibilityService.apk";
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
+ DeviceNotAvailableException, BuildError {
+ if (!(buildInfo instanceof IFolderBuildInfo)) {
+ throw new IllegalArgumentException("Provided buildInfo is not a IFolderBuildInfo");
+ }
+ Log.i(LOG_TAG, String.format("Setting up %s to run CTS tests", device.getSerialNumber()));
+
+ IFolderBuildInfo ctsBuild = (IFolderBuildInfo)buildInfo;
+ try {
+ CtsBuildHelper buildHelper = new CtsBuildHelper(ctsBuild.getRootDir());
+
+ if (!device.enableAdbRoot()) {
+ throw new TargetSetupError(String.format(
+ "Failed to set root on device %s.", device.getSerialNumber()));
+ }
+
+ // perform CTS setup steps that only work if adb is root
+
+ // TODO: turn on mock locations
+ enableAccessibilityService(device, buildHelper);
+
+ // end root setup steps
+ } catch (FileNotFoundException e) {
+ throw new TargetSetupError("Invalid CTS installation", e);
+ }
+ }
+
+ private void enableAccessibilityService(ITestDevice device, CtsBuildHelper ctsBuild)
+ throws DeviceNotAvailableException, TargetSetupError,
+ FileNotFoundException {
+ String errorCode = device.installPackage(
+ ctsBuild.getTestApp(ACCESSIBILITY_SERVICE_APK_FILE_NAME), true);
+ if (errorCode != null) {
+ // TODO: retry ?
+ throw new TargetSetupError(String.format(
+ "Failed to install %s on device %s. Reason: %s",
+ ACCESSIBILITY_SERVICE_APK_FILE_NAME, device.getSerialNumber(), errorCode));
+ }
+ // TODO: enable Settings > Accessibility > Accessibility > Delegating Accessibility
+ // Service
+ }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/targetsetup/CtsSetup.java b/tools/tradefed-host/src/com/android/cts/tradefed/targetsetup/CtsSetup.java
new file mode 100644
index 0000000..77b4656
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/targetsetup/CtsSetup.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2010 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.targetsetup;
+
+import com.android.cts.tradefed.testtype.PlanTest;
+import com.android.tradefed.config.ConfigurationException;
+import com.android.tradefed.config.IConfiguration;
+import com.android.tradefed.config.IConfigurationReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.targetsetup.BuildError;
+import com.android.tradefed.targetsetup.IBuildInfo;
+import com.android.tradefed.targetsetup.IFolderBuildInfo;
+import com.android.tradefed.targetsetup.ITargetPreparer;
+import com.android.tradefed.targetsetup.TargetSetupError;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/**
+ * A {@link ITargetPreparer} that sets up a device for CTS testing.
+ * <p/>
+ * All the actions performed in this class must work on a production device.
+ */
+public class CtsSetup implements ITargetPreparer, IConfigurationReceiver {
+
+ private static final String RUNNER_APK_NAME = "android.core.tests.runner.apk";
+ // TODO: read this from configuration file rather than hardcoding
+ private static final String TEST_STUBS_APK = "CtsTestStubs.apk";
+
+ private IConfiguration mConfiguration = null;
+
+ /**
+ * Factory method to create a {@link CtsBuildHelper}.
+ * <p/>
+ * Exposed for unit testing.
+ */
+ CtsBuildHelper createBuildHelper(File rootDir) throws FileNotFoundException {
+ return new CtsBuildHelper(rootDir);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setConfiguration(IConfiguration configuration) {
+ mConfiguration = configuration;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
+ BuildError, DeviceNotAvailableException {
+ if (!(buildInfo instanceof IFolderBuildInfo)) {
+ throw new IllegalArgumentException("Provided buildInfo is not a IFolderBuildInfo");
+ }
+ if (mConfiguration == null) {
+ throw new IllegalStateException("setConfiguration() was not called before setUp");
+ }
+ IFolderBuildInfo ctsBuildInfo = (IFolderBuildInfo)buildInfo;
+ try {
+ CtsBuildHelper buildHelper = createBuildHelper(ctsBuildInfo.getRootDir());
+ // pass necessary build information to the other config objects
+ mConfiguration.injectOptionValue(PlanTest.TEST_CASES_DIR_OPTION,
+ buildHelper.getTestCasesDir().getAbsolutePath());
+ mConfiguration.injectOptionValue(PlanTest.TEST_PLANS_DIR_OPTION,
+ buildHelper.getTestPlansDir().getAbsolutePath());
+ installCtsPrereqs(device, buildHelper);
+ } catch (FileNotFoundException e) {
+ throw new TargetSetupError("Invalid CTS installation", e);
+ } catch (ConfigurationException e) {
+ throw new TargetSetupError("Failed to set repository directory options", e);
+ }
+ }
+
+ /**
+ * Installs an apkFile on device.
+ *
+ * @param device the {@link ITestDevice}
+ * @param apkFile the apk {@link File}
+ * @throws DeviceNotAvailableException
+ * @throws TargetSetupError if apk cannot be installed successfully
+ */
+ void installApk(ITestDevice device, File apkFile)
+ throws DeviceNotAvailableException, TargetSetupError {
+ String errorCode = device.installPackage(apkFile, true);
+ if (errorCode != null) {
+ // TODO: retry ?
+ throw new TargetSetupError(String.format(
+ "Failed to install %s on device %s. Reason: %s", apkFile.getName(),
+ device.getSerialNumber(), errorCode));
+ }
+ }
+
+ /**
+ * Install pre-requisite apks for running tests
+ *
+ * @throws TargetSetupError if the pre-requisite apks fail to install
+ * @throws DeviceNotAvailableException
+ * @throws FileNotFoundException
+ */
+ private void installCtsPrereqs(ITestDevice device, CtsBuildHelper ctsBuild)
+ throws DeviceNotAvailableException, TargetSetupError, FileNotFoundException {
+ installApk(device, ctsBuild.getTestApp(TEST_STUBS_APK));
+ installApk(device, ctsBuild.getTestApp(RUNNER_APK_NAME));
+ }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/IPlanXmlParser.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/IPlanXmlParser.java
new file mode 100644
index 0000000..f7d4ab1
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/IPlanXmlParser.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010 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.tradefed.util.xml.AbstractXmlParser.ParseException;
+
+import java.io.InputStream;
+import java.util.Collection;
+
+/**
+ * Interface for accessing test plan data.
+ */
+interface IPlanXmlParser {
+
+ /**
+ * Parse the test plan data from given stream.
+ *
+ * @param xmlStream the {@link InputStream} that contains the test plan xml.
+ */
+ public void parse(InputStream xmlStream) throws ParseException;
+
+ /**
+ * Gets the list of test uris parsed from the plan.
+ * <p/>
+ * Must be called after {@link IPlanXmlParser#parse(InputStream)}.
+ */
+ public Collection<String> getTestUris();
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestCaseRepo.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestCaseRepo.java
new file mode 100644
index 0000000..18ea7cf
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestCaseRepo.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010 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.tradefed.testtype.IRemoteTest;
+
+import java.util.Collection;
+
+/**
+ * Interface for accessing tests from the CTS repository.
+ */
+interface ITestCaseRepo {
+
+ /**
+ * Gets a list of tests identified by given list of uris
+ *
+ * @param testUris the string uris
+ * @return a {@link Collection} of {@link IRemoteTest}
+ */
+ public Collection<IRemoteTest> getTests(Collection<String> testUris);
+
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/JarHostTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/JarHostTest.java
new file mode 100644
index 0000000..70b8432
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/JarHostTest.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2010 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.Log;
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.result.JUnitToInvocationResultForwarder;
+import com.android.tradefed.testtype.AbstractRemoteTest;
+import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.util.CommandStatus;
+import com.android.tradefed.util.RunUtil;
+import com.android.tradefed.util.IRunUtil.IRunnableResult;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+
+/**
+ * A {@link IRemoteTest} that can run a set of JUnit tests from a jar.
+ */
+public class JarHostTest extends AbstractRemoteTest implements IDeviceTest {
+
+ private static final String LOG_TAG = "JarHostTest";
+
+ private ITestDevice mDevice;
+ private File mJarFile;
+ private Collection<TestIdentifier> mTests;
+ private long mTimeoutMs = 10 * 60 * 1000;
+ private String mRunName;
+ private String mTestAppPath;
+
+ /**
+ * Set the jar file to load tests from.
+ * @param jarFile
+ */
+ void setJarFile(File jarFile) {
+ mJarFile = jarFile;
+ }
+
+ /**
+ * Sets the collection of tests to run
+ * @param tests
+ */
+ void setTests(Collection<TestIdentifier> tests) {
+ mTests = tests;
+ }
+
+ /**
+ * Set the maximum time in ms each test should run.
+ * <p/>
+ * Tests that take longer than this amount will be failed with a {@link TestTimeoutException}
+ * as the cause.
+ *
+ * @param testTimeout
+ */
+ void setTimeout(long testTimeoutMs) {
+ mTimeoutMs = testTimeoutMs;
+ }
+
+ /**
+ * Set the run name to report to {@link ITestInvocationListener#testRunStarted(String, int)}
+ *
+ * @param runName
+ */
+ void setRunName(String runName) {
+ mRunName = runName;
+ }
+
+ /**
+ * Set the filesystem path to test app artifacts needed to run tests.
+ *
+ * @see {@link com.android.hosttest.DeviceTest#setTestAppPath(String)}
+ *
+ * @param testAppPath
+ */
+ void setTestAppPath(String testAppPath) {
+ mTestAppPath = testAppPath;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ITestDevice getDevice() {
+ return mDevice;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setDevice(ITestDevice device) {
+ mDevice = device;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int countTestCases() {
+ if (mTests == null) {
+ throw new IllegalStateException();
+ }
+ return mTests.size();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void run(List<ITestInvocationListener> listeners) throws DeviceNotAvailableException {
+ checkFields();
+ Log.i(LOG_TAG, String.format("Running %s test package from jar, contains %d tests.",
+ mRunName, countTestCases()));
+ // create a junit listener to forward the JUnit test results to the
+ // {@link ITestInvocationListener}s
+ JUnitToInvocationResultForwarder resultForwarder =
+ new JUnitToInvocationResultForwarder(listeners);
+ TestResult junitResult = new TestResult();
+ junitResult.addListener(resultForwarder);
+ long startTime = System.currentTimeMillis();
+ reportRunStarted(listeners);
+ for (TestIdentifier testId : mTests) {
+ Test junitTest = loadTest(testId.getClassName(), testId.getTestName());
+ if (junitTest != null) {
+ runTest(testId, junitTest, junitResult);
+ }
+ }
+ reportRunEnded(System.currentTimeMillis() - startTime, listeners);
+ }
+
+ /**
+ * Report the start of the test run.
+ *
+ * @param listeners
+ */
+ private void reportRunStarted(List<ITestInvocationListener> listeners) {
+ for (ITestInvocationListener listener : listeners) {
+ listener.testRunStarted(mRunName, countTestCases());
+ }
+ }
+
+ /**
+ * Run test with timeout support.
+ */
+ private void runTest(TestIdentifier testId, final Test junitTest, final TestResult junitResult) {
+ if (junitTest instanceof IDeviceTest) {
+ ((IDeviceTest)junitTest).setDevice(getDevice());
+ } else if (junitTest instanceof com.android.hosttest.DeviceTest) {
+ // legacy check - see if test uses hosttestlib. This check should go away once
+ // all host tests are converted to use tradefed
+ com.android.hosttest.DeviceTest deviceTest = (com.android.hosttest.DeviceTest)junitTest;
+ deviceTest.setDevice(getDevice().getIDevice());
+ deviceTest.setTestAppPath(mTestAppPath);
+ }
+ CommandStatus status = RunUtil.getInstance().runTimed(mTimeoutMs, new IRunnableResult() {
+
+ @Override
+ public boolean run() throws Exception {
+ junitTest.run(junitResult);
+ return true;
+ }
+
+ @Override
+ public void cancel() {
+ // ignore
+ }
+ });
+ if (status.equals(CommandStatus.TIMED_OUT)) {
+ junitResult.addError(junitTest, new TestTimeoutException());
+ junitResult.endTest(junitTest);
+ }
+ }
+
+ /**
+ * Report the end of the test run.
+ *
+ * @param elapsedTime
+ * @param listeners
+ */
+ @SuppressWarnings("unchecked")
+ private void reportRunEnded(long elapsedTime, List<ITestInvocationListener> listeners) {
+ for (ITestInvocationListener listener : listeners) {
+ listener.testRunEnded(elapsedTime, Collections.EMPTY_MAP);
+ }
+ }
+
+ /**
+ * Load the test with given names from the jar.
+ *
+ * @param className
+ * @param testName
+ * @return the loaded {@link Test} or <code>null</code> if test could not be loaded.
+ */
+ private Test loadTest(String className, String testName) {
+ try {
+ URL urls[] = {mJarFile.getCanonicalFile().toURI().toURL()};
+ Class<?> testClass = loadClass(className, urls);
+
+ if (TestCase.class.isAssignableFrom(testClass)) {
+ TestCase testCase = (TestCase)testClass.newInstance();
+ testCase.setName(testName);
+ return testCase;
+ } else if (Test.class.isAssignableFrom(testClass)) {
+ Test test = (Test)testClass.newInstance();
+ return test;
+ } else {
+ Log.e(LOG_TAG, String.format("Class '%s' from jar '%s' is not a Test",
+ className, mJarFile.getAbsolutePath()));
+ }
+ } catch (ClassNotFoundException e) {
+ reportLoadError(mJarFile, className, e);
+ } catch (IllegalAccessException e) {
+ reportLoadError(mJarFile, className, e);
+ } catch (IOException e) {
+ reportLoadError(mJarFile, className, e);
+ } catch (InstantiationException e) {
+ reportLoadError(mJarFile, className, e);
+ }
+ return null;
+ }
+
+ /**
+ * Loads a class from given URLs.
+ * <p/>
+ * Exposed so unit tests can mock
+ *
+ * @param className
+ * @param urls
+ * @return
+ * @throws ClassNotFoundException
+ */
+ Class<?> loadClass(String className, URL[] urls) throws ClassNotFoundException {
+ URLClassLoader cl = new URLClassLoader(urls);
+ Class<?> testClass = cl.loadClass(className);
+ return testClass;
+ }
+
+ private void reportLoadError(File jarFile, String className, Exception e) {
+ Log.e(LOG_TAG, String.format("Failed to load test class '%s' from jar '%s'",
+ className, jarFile.getAbsolutePath()));
+ Log.e(LOG_TAG, e);
+ }
+
+ /**
+ * Checks that all mandatory member fields has been set.
+ */
+ private void checkFields() {
+ if (mRunName == null) {
+ throw new IllegalArgumentException("run name has not been set");
+ }
+ if (mDevice == null) {
+ throw new IllegalArgumentException("Device has not been set");
+ }
+ if (mJarFile == null) {
+ throw new IllegalArgumentException("jar file has not been set");
+ }
+ if (mTests == null) {
+ throw new IllegalArgumentException("tests has not been set");
+ }
+ }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/PlanTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/PlanTest.java
new file mode 100644
index 0000000..212eb66
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/PlanTest.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2010 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.device.DeviceInfoCollector;
+import com.android.ddmlib.Log;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.testtype.AbstractRemoteTest;
+import com.android.tradefed.testtype.IDeviceTest;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.util.xml.AbstractXmlParser.ParseException;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.List;
+
+import junit.framework.Test;
+
+/**
+ * A {@link Test} that runs all the tests in the CTS test plan with given name
+ */
+public class PlanTest extends AbstractRemoteTest implements IDeviceTest, IRemoteTest {
+
+ private static final String LOG_TAG = "PlanTest";
+
+ public static final String TEST_CASES_DIR_OPTION = "test-cases-path";
+ public static final String TEST_PLANS_DIR_OPTION = "test-plans-path";
+
+ private ITestDevice mDevice;
+
+ @Option(name = "plan", description = "the test plan to run")
+ private String mPlanName = null;
+
+ @Option(name = TEST_CASES_DIR_OPTION, description =
+ "file path to directory containing CTS test cases")
+ private File mTestCaseDir = null;
+
+ @Option(name = TEST_PLANS_DIR_OPTION, description =
+ "file path to directory containing CTS test plans")
+ private File mTestPlanDir = null;
+
+ /**
+ * {@inheritDoc}
+ */
+ public ITestDevice getDevice() {
+ return mDevice;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setDevice(ITestDevice device) {
+ mDevice = device;
+ }
+
+ /**
+ * Set the test plan directory.
+ * <p/>
+ * Exposed for unit testing
+ */
+ void setTestPlanDir(File planDir) {
+ mTestPlanDir = planDir;
+ }
+
+ /**
+ * Set the test case directory.
+ * <p/>
+ * Exposed for unit testing
+ */
+ void setTestCaseDir(File testCaseDir) {
+ mTestCaseDir = testCaseDir;
+ }
+
+ /**
+ * Set the plan name to run.
+ * <p/>
+ * Exposed for unit testing
+ */
+ void setPlanName(String planName) {
+ mPlanName = planName;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run(List<ITestInvocationListener> listeners) throws DeviceNotAvailableException {
+ if (mPlanName == null) {
+ throw new IllegalArgumentException("missing --plan option");
+ }
+ if (getDevice() == null) {
+ throw new IllegalArgumentException("missing device");
+ }
+ if (mTestCaseDir == null) {
+ throw new IllegalArgumentException(String.format("missing %s option",
+ TEST_CASES_DIR_OPTION));
+ }
+ if (mTestPlanDir == null) {
+ throw new IllegalArgumentException(String.format("missing %s", TEST_PLANS_DIR_OPTION));
+ }
+
+ Log.i(LOG_TAG, String.format("Executing CTS test plan %s", mPlanName));
+
+ try {
+ String ctsPlanRelativePath = String.format("%s.xml", mPlanName);
+ File ctsPlanFile = new File(mTestPlanDir, ctsPlanRelativePath);
+ IPlanXmlParser parser = createXmlParser();
+ parser.parse(createXmlStream(ctsPlanFile));
+ Collection<String> testUris = parser.getTestUris();
+ ITestCaseRepo testRepo = createTestCaseRepo();
+ Collection<IRemoteTest> tests = testRepo.getTests(testUris);
+ collectDeviceInfo(getDevice(), mTestCaseDir, listeners);
+ for (IRemoteTest test : tests) {
+ if (test instanceof IDeviceTest) {
+ ((IDeviceTest)test).setDevice(getDevice());
+ }
+ test.run(listeners);
+ }
+ } catch (FileNotFoundException e) {
+ throw new IllegalArgumentException("failed to find CTS plan file", e);
+ } catch (ParseException e) {
+ throw new IllegalArgumentException("failed to parse CTS plan file", e);
+ }
+ }
+
+ /**
+ * Runs the device info collector instrumentation on device, and forwards it to test listeners
+ * as run metrics.
+ *
+ * @param listeners
+ * @throws DeviceNotAvailableException
+ */
+ private void collectDeviceInfo(ITestDevice device, File testApkDir,
+ List<ITestInvocationListener> listeners) throws DeviceNotAvailableException {
+ DeviceInfoCollector.collectDeviceInfo(device, testApkDir, listeners);
+ }
+
+ /**
+ * Factory method for creating a {@link ITestCaseRepo}.
+ * <p/>
+ * Exposed for unit testing
+ */
+ ITestCaseRepo createTestCaseRepo() {
+ return new TestCaseRepo(mTestCaseDir);
+ }
+
+ /**
+ * Factory method for creating a {@link PlanXmlParser}.
+ * <p/>
+ * Exposed for unit testing
+ */
+ IPlanXmlParser createXmlParser() {
+ return new PlanXmlParser();
+ }
+
+ /**
+ * Factory method for creating a {@link InputStream} from a plan xml file.
+ * <p/>
+ * Exposed for unit testing
+ */
+ InputStream createXmlStream(File xmlFile) throws FileNotFoundException {
+ return new BufferedInputStream(new FileInputStream(xmlFile));
+ }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/PlanXmlParser.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/PlanXmlParser.java
new file mode 100644
index 0000000..fd3dcb8
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/PlanXmlParser.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010 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.tradefed.util.xml.AbstractXmlParser;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * Parses a test plan xml file.
+ */
+class PlanXmlParser extends AbstractXmlParser implements IPlanXmlParser {
+
+ private Set<String> mUris;
+
+ /**
+ * SAX callback object. Handles parsing data from the xml tags.
+ */
+ private class EntryHandler extends DefaultHandler {
+
+ private static final String ENTRY_TAG = "Entry";
+
+ @Override
+ public void startElement(String uri, String localName, String name, Attributes attributes)
+ throws SAXException {
+ if (ENTRY_TAG.equals(localName)) {
+ final String entryUriValue = attributes.getValue("uri");
+ mUris.add(entryUriValue);
+ }
+ }
+ }
+
+ PlanXmlParser() {
+ // Uses a LinkedHashSet to have predictable iteration order
+ mUris = new LinkedHashSet<String>();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Collection<String> getTestUris() {
+ return mUris;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected DefaultHandler createXmlHandler() {
+ return new EntryHandler();
+ }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestCaseRepo.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestCaseRepo.java
new file mode 100644
index 0000000..8392762
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestCaseRepo.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2010 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.Log;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.util.xml.AbstractXmlParser.ParseException;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FilenameFilter;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.Map;
+
+/**
+ * Retrieves CTS test case definitions from the repository.
+ */
+class TestCaseRepo implements ITestCaseRepo {
+
+ private static final String LOG_TAG = "TestCaseRepo";
+
+ private File mTestCaseDir;
+
+ /** mapping of uri to test definition */
+ private Map<String, TestPackageDef> mTestMap;
+
+ /**
+ * Creates a {@link TestCaseRepo}, initialized from provided repo files
+ *
+ * @param testCaseDir directory containing all test case definition xml and build files
+ */
+ public TestCaseRepo(File testCaseDir) {
+ mTestCaseDir = testCaseDir;
+ mTestMap = new Hashtable<String, TestPackageDef>();
+ parse(mTestCaseDir);
+ }
+
+ /**
+ * Builds mTestMap based on directory contents
+ */
+ private void parse(File dir) {
+ File[] xmlFiles = dir.listFiles(new XmlFilter());
+ for (File xmlFile : xmlFiles) {
+ parseTestFromXml(xmlFile);
+ }
+ }
+
+ /**
+ * @param xmlFile
+ * @throws ParseException
+ */
+ private void parseTestFromXml(File xmlFile) {
+ TestPackageXmlParser parser = new TestPackageXmlParser();
+ try {
+ parser.parse(createStreamFromFile(xmlFile));
+ TestPackageDef def = parser.getTestPackageDef();
+ if (def != null) {
+ mTestMap.put(def.getUri(), def);
+ } else {
+ Log.w(LOG_TAG, String.format("Could not find test package info in xml file %s",
+ xmlFile.getAbsolutePath()));
+ }
+ } catch (FileNotFoundException e) {
+ Log.e(LOG_TAG, String.format("Could not find test case xml file %s",
+ xmlFile.getAbsolutePath()));
+ Log.e(LOG_TAG, e);
+ } catch (ParseException e) {
+ Log.e(LOG_TAG, String.format("Failed to parse test case xml file %s",
+ xmlFile.getAbsolutePath()));
+ Log.e(LOG_TAG, e);
+ }
+ }
+
+ /**
+ * Helper method to create a stream to read data from given file
+ * <p/>
+ * Exposed for unit testing
+ *
+ * @param xmlFile
+ * @return
+ *
+ */
+ InputStream createStreamFromFile(File xmlFile) throws FileNotFoundException {
+ return new BufferedInputStream(new FileInputStream(xmlFile));
+ }
+
+ private static class XmlFilter implements FilenameFilter {
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".xml");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Collection<IRemoteTest> getTests(Collection<String> testUris) {
+ Collection<IRemoteTest> tests = new ArrayList<IRemoteTest>(testUris.size());
+ for (String uri : testUris) {
+ TestPackageDef def = mTestMap.get(uri);
+ if (def != null) {
+ IRemoteTest test = def.createTest(mTestCaseDir);
+ if (test != null) {
+ tests.add(test);
+ } else {
+ Log.w(LOG_TAG, String.format("Failed to create test from package uri %s", uri));
+ }
+ } else {
+ Log.w(LOG_TAG, String.format("Could not find test with uri %s", uri));
+ }
+ }
+ return tests;
+ }
+}
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
new file mode 100644
index 0000000..a75295e
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2010 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.Log;
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.testtype.InstrumentationTest;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * Container for CTS test info.
+ * <p/>
+ * Knows how to translate this info into a runnable {@link IRemoteTest}.
+ */
+public class TestPackageDef {
+
+ private static final String LOG_TAG = "TestPackageDef";
+
+ private String mUri = null;
+ private String mAppNameSpace = null;
+ private String mName = null;
+ private String mRunner = null;
+ private boolean mIsHostSideTest = false;
+ private String mJarPath = null;
+ private boolean mIsSignatureTest = false;
+ private boolean mIsReferenceAppTest = false;
+
+ private Collection<TestIdentifier> mTests = new ArrayList<TestIdentifier>();
+
+ void setUri(String uri) {
+ mUri = uri;
+ }
+
+ /**
+ * Get the unique URI of the test package.
+ * @return the {@link String} uri
+ */
+ public String getUri() {
+ return mUri;
+ }
+
+ void setAppNameSpace(String appNameSpace) {
+ mAppNameSpace = appNameSpace;
+ }
+
+ String getAppNameSpace() {
+ return mAppNameSpace;
+ }
+
+ void setName(String name) {
+ mName = name;
+ }
+
+ String getName() {
+ return mName;
+ }
+
+ void setRunner(String runnerName) {
+ mRunner = runnerName;
+ }
+
+ String getRunner() {
+ return mRunner;
+ }
+
+ void setIsHostSideTest(boolean hostSideTest) {
+ mIsHostSideTest = hostSideTest;
+
+ }
+
+ boolean isHostSideTest() {
+ return mIsHostSideTest;
+ }
+
+ void setJarPath(String jarPath) {
+ mJarPath = jarPath;
+ }
+
+ String getJarPath() {
+ return mJarPath;
+ }
+
+ void setIsSignatureCheck(boolean isSignatureCheckTest) {
+ mIsSignatureTest = isSignatureCheckTest;
+ }
+
+ boolean isSignatureCheck() {
+ return mIsSignatureTest;
+ }
+
+ void setIsReferenceApp(boolean isReferenceApp) {
+ mIsReferenceAppTest = isReferenceApp;
+ }
+
+ boolean isReferenceApp() {
+ return mIsReferenceAppTest;
+ }
+
+ /**
+ * Creates a runnable {@link IRemoteTest} from info stored in this definition.
+ *
+ * @param testCaseDir {@link File} representing directory of test case data
+ * @return a {@link IRemoteTest} with all necessary data populated to run the test or
+ * <code>null</code> if test could not be created
+ */
+ public IRemoteTest createTest(File testCaseDir) {
+ if (mIsHostSideTest) {
+ Log.d(LOG_TAG, String.format("Creating host test for %s", mName));
+ JarHostTest hostTest = new JarHostTest();
+ hostTest.setRunName(mName);
+ hostTest.setJarFile(new File(testCaseDir, mJarPath));
+ hostTest.setTestAppPath(testCaseDir.getAbsolutePath());
+ hostTest.setTests(mTests);
+ return hostTest;
+ } else if (mIsSignatureTest) {
+ // TODO: implement this
+ Log.w(LOG_TAG, String.format("Skipping currently unsupported signature test %s",
+ mName));
+ return null;
+ } else if (mIsReferenceAppTest) {
+ // TODO: implement this
+ Log.w(LOG_TAG, String.format("Skipping currently unsupported reference app test %s",
+ mName));
+ return null;
+ } else {
+ Log.d(LOG_TAG, String.format("Creating instrumentation test for %s", mName));
+ InstrumentationTest instrTest = new InstrumentationTest();
+ instrTest.setPackageName(mAppNameSpace);
+ instrTest.setRunnerName(mRunner);
+ // mName means 'apk file name' for instrumentation tests
+ File apkFile = new File(testCaseDir, String.format("%s.apk", mName));
+ if (!apkFile.exists()) {
+ Log.w(LOG_TAG, String.format("Could not find apk file %s",
+ apkFile.getAbsolutePath()));
+ return null;
+ }
+ instrTest.setInstallFile(apkFile);
+ return instrTest;
+ }
+ }
+
+ /**
+ * Add a {@link TestDef} to the list of tests in this package.
+ *
+ * @param testdef
+ */
+ void addTest(TestIdentifier testDef) {
+ mTests.add(testDef);
+ }
+
+ /**
+ * Get the collection of tests in this test package.
+ * <p/>
+ * Exposed for unit testing.
+ */
+ Collection<TestIdentifier> getTests() {
+ return mTests;
+ }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageXmlParser.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageXmlParser.java
new file mode 100644
index 0000000..9bf6968
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageXmlParser.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2010 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.Log;
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.util.xml.AbstractXmlParser;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import java.util.Iterator;
+import java.util.Stack;
+
+/**
+ * Parser for CTS test case XML.
+ * <p/>
+ * Dumb parser that just retrieves data from in the test case xml and stuff it into a
+ * {@link TestPackageDef}. Currently performs limited error checking.
+ */
+public class TestPackageXmlParser extends AbstractXmlParser {
+
+ private static final String LOG_TAG = "TestPackageXmlParser";
+
+ private TestPackageDef mPackageDef;
+
+ /**
+ * SAX callback object. Handles parsing data from the xml tags.
+ * <p/>
+ * Expected structure:
+ * <TestPackage>
+ * <TestSuite ...>
+ * <TestCase>
+ * <Test>
+ */
+ private class TestPackageHandler extends DefaultHandler {
+
+ private static final String TEST_PACKAGE_TAG = "TestPackage";
+ private static final String TEST_SUITE_TAG = "TestSuite";
+ private static final String TEST_CASE_TAG = "TestCase";
+ private static final String TEST_TAG = "Test";
+
+ // holds current class name segments
+ private Stack<String> mClassNameStack = new Stack<String>();
+
+ @Override
+ public void startElement(String uri, String localName, String name, Attributes attributes)
+ throws SAXException {
+ if (TEST_PACKAGE_TAG.equals(localName)) {
+ // appPackageName is used as the uri
+ final String entryUriValue = attributes.getValue("appPackageName");
+ final String testPackageNameSpace = attributes.getValue("appNameSpace");
+ final String packageName = attributes.getValue("name");
+ final String runnerName = attributes.getValue("runner");
+ final String hostSideTest = attributes.getValue("hostSideOnly");
+ final String jarPath = attributes.getValue("jarPath");
+ final String signatureCheck = attributes.getValue("signatureCheck");
+ final String referenceApp = attributes.getValue("referenceAppTest");
+
+ mPackageDef = new TestPackageDef();
+ mPackageDef.setUri(entryUriValue);
+ mPackageDef.setAppNameSpace(testPackageNameSpace);
+ mPackageDef.setName(packageName);
+ mPackageDef.setRunner(runnerName);
+ mPackageDef.setIsHostSideTest(parseBoolean(hostSideTest));
+ mPackageDef.setJarPath(jarPath);
+ mPackageDef.setIsSignatureCheck(parseBoolean(signatureCheck));
+ mPackageDef.setIsReferenceApp(parseBoolean(referenceApp));
+
+ // reset the class name
+ mClassNameStack = new Stack<String>();
+ } else if (TEST_SUITE_TAG.equals(localName)) {
+ String packageSegment = attributes.getValue("name");
+ if (packageSegment != null) {
+ mClassNameStack.push(packageSegment);
+ } else {
+ Log.e(LOG_TAG, String.format("Invalid XML: missing 'name' attribute for '%s'",
+ TEST_SUITE_TAG));
+ }
+ } else if (TEST_CASE_TAG.equals(localName)) {
+ String classSegment = attributes.getValue("name");
+ if (classSegment != null) {
+ mClassNameStack.push(classSegment);
+ } else {
+ Log.e(LOG_TAG, String.format("Invalid XML: missing 'name' attribute for '%s'",
+ TEST_CASE_TAG));
+ }
+ } else if (TEST_TAG.equals(localName)) {
+ String methodName = attributes.getValue("name");
+ if (mPackageDef == null) {
+ Log.e(LOG_TAG, String.format(
+ "Invalid XML: encountered a '%s' tag not enclosed within a '%s' tag",
+ TEST_TAG, TEST_PACKAGE_TAG));
+ } else if (methodName == null) {
+ Log.e(LOG_TAG, String.format("Invalid XML: missing 'name' attribute for '%s'",
+ TEST_TAG));
+ } else {
+ // build class name from package segments
+ StringBuilder classNameBuilder = new StringBuilder();
+ for (Iterator<String> iter = mClassNameStack.iterator(); iter.hasNext(); ) {
+ classNameBuilder.append(iter.next());
+ if (iter.hasNext()) {
+ classNameBuilder.append(".");
+ }
+ }
+ TestIdentifier testdef = new TestIdentifier(classNameBuilder.toString(),
+ methodName);
+ mPackageDef.addTest(testdef);
+ }
+ }
+
+ }
+
+ @Override
+ public void endElement (String uri, String localName, String qName) throws SAXException {
+ if (TEST_SUITE_TAG.equals(localName) || TEST_CASE_TAG.equals(localName)) {
+ mClassNameStack.pop();
+ }
+ }
+
+ /**
+ * Parse a boolean attribute value
+ */
+ private boolean parseBoolean(final String stringValue) {
+ return stringValue != null &&
+ Boolean.parseBoolean(stringValue);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected DefaultHandler createXmlHandler() {
+ return new TestPackageHandler();
+ }
+
+ /**
+ * @returns the {@link TestPackageDef} containing data parsed from xml or <code>null</code> if
+ * xml did not contain the correct information.
+ */
+ public TestPackageDef getTestPackageDef() {
+ return mPackageDef;
+ }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestTimeoutException.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestTimeoutException.java
new file mode 100644
index 0000000..c436658
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestTimeoutException.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 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;
+
+/**
+ * An exception that indicates a test has timed out.
+ * TODO: consider moving this to tradefed proper
+ */
+public class TestTimeoutException extends Exception {
+
+ private static final long serialVersionUID = 941691916057121118L;
+
+}
diff --git a/tools/tradefed-host/tests/.classpath b/tools/tradefed-host/tests/.classpath
new file mode 100644
index 0000000..b130096
--- /dev/null
+++ b/tools/tradefed-host/tests/.classpath
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/easymock"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/ddmlib"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/tradefederation"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/cts-tradefed-host"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/tools/tradefed-host/tests/.project b/tools/tradefed-host/tests/.project
new file mode 100644
index 0000000..1c385d8
--- /dev/null
+++ b/tools/tradefed-host/tests/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>cts-tradefed-host-tests</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/tools/tradefed-host/tests/Android.mk b/tools/tradefed-host/tests/Android.mk
new file mode 100644
index 0000000..d3b94cd
--- /dev/null
+++ b/tools/tradefed-host/tests/Android.mk
@@ -0,0 +1,29 @@
+# Copyright (C) 2010 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)
+
+# Only compile source java files in this lib.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE := cts-tradefed-tests
+LOCAL_MODULE_TAGS := optional
+LOCAL_JAVA_LIBRARIES := ddmlib-prebuilt tradefed-prebuilt cts-tradefed
+LOCAL_STATIC_JAVA_LIBRARIES := easymock
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/device/DeviceInfoCollectorFuncTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/device/DeviceInfoCollectorFuncTest.java
new file mode 100644
index 0000000..54f8f98
--- /dev/null
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/device/DeviceInfoCollectorFuncTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010 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.device;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.result.CollectingTestListener;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.targetsetup.BuildInfo;
+import com.android.tradefed.testtype.DeviceTestCase;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Functional test for {@link DeviceInfoCollector}.
+ * <p/>
+ * TODO: this test assumes the TestDeviceSetup apk is located in the "java.io.tmpdir"
+ */
+public class DeviceInfoCollectorFuncTest extends DeviceTestCase {
+
+ public void testCollectDeviceInfo() throws DeviceNotAvailableException {
+ CollectingTestListener testListener = new CollectingTestListener();
+
+ testListener.invocationStarted(new BuildInfo());
+ List<ITestInvocationListener> listeners = new ArrayList<ITestInvocationListener>(1);
+ listeners.add(testListener);
+ DeviceInfoCollector.collectDeviceInfo(getDevice(), new File(
+ System.getProperty("java.io.tmpdir")),
+ listeners);
+ assertNotNull(testListener.getCurrentRunResults());
+ assertTrue(testListener.getCurrentRunResults().getRunMetrics().size() > 0);
+ for (Map.Entry<String, String> metricEntry : testListener.getCurrentRunResults().getRunMetrics().entrySet()) {
+ System.out.println(String.format("%s=%s", metricEntry.getKey(), metricEntry.getValue()));
+ }
+ testListener.invocationEnded(0);
+ }
+}
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/CtsXmlResultReporterTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/CtsXmlResultReporterTest.java
new file mode 100644
index 0000000..113496c
--- /dev/null
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/CtsXmlResultReporterTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2010 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.result;
+
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.ddmlib.testrunner.ITestRunListener.TestFailure;
+import com.android.tradefed.result.XmlResultReporter;
+import com.android.tradefed.targetsetup.BuildInfo;
+import com.android.tradefed.util.FileUtil;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link XmlResultReporter}.
+ */
+public class CtsXmlResultReporterTest extends TestCase {
+
+ private CtsXmlResultReporter mResultReporter;
+ private ByteArrayOutputStream mOutputStream;
+ private File mReportDir;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mOutputStream = new ByteArrayOutputStream();
+ mResultReporter = new CtsXmlResultReporter() {
+ @Override
+ OutputStream createOutputResultStream(File reportDir) throws IOException {
+ return mOutputStream;
+ }
+
+ @Override
+ String getTimestamp() {
+ return "ignore";
+ }
+ };
+ // TODO: use mock file dir instead
+ mReportDir = FileUtil.createTempDir("foo");
+ mResultReporter.setReportDir(mReportDir);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ if (mReportDir != null) {
+ FileUtil.recursiveDelete(mReportDir);
+ }
+ super.tearDown();
+ }
+
+ /**
+ * A simple test to ensure expected output is generated for test run with no tests.
+ */
+ public void testEmptyGeneration() {
+ final String expectedOutput = "<?xml version='1.0' encoding='UTF-8' standalone='no' ?>" +
+ "<?xml-stylesheet type=\"text/xsl\" href=\"cts_result.xsl\"?>" +
+ "<TestResult testPlan=\"unknown\" profile=\"unknown\" starttime=\"ignore\" endtime=\"ignore\" version=\"2.0\"> " +
+ "<Summary failed=\"0\" notExecuted=\"0\" timeout=\"0\" omitted=\"0\" pass=\"0\" total=\"0\" />" +
+ "</TestResult>";
+ mResultReporter.invocationStarted(new BuildInfo(1, "test", "test"));
+ mResultReporter.invocationEnded(1);
+ assertEquals(expectedOutput, getOutput());
+ }
+
+ /**
+ * A simple test to ensure expected output is generated for test run with a single passed test.
+ */
+ public void testSinglePass() {
+ Map<String, String> emptyMap = Collections.emptyMap();
+ final TestIdentifier testId = new TestIdentifier("com.foo.FooTest", "testFoo");
+ mResultReporter.invocationStarted(new BuildInfo());
+ mResultReporter.testRunStarted("run", 1);
+ mResultReporter.testStarted(testId);
+ mResultReporter.testEnded(testId, emptyMap);
+ mResultReporter.testRunEnded(3000, emptyMap);
+ mResultReporter.invocationEnded(1);
+ String output = getOutput();
+ // TODO: consider doing xml based compare
+ assertTrue(output.contains(
+ "<Summary failed=\"0\" notExecuted=\"0\" timeout=\"0\" omitted=\"0\" pass=\"1\" total=\"1\" />"));
+ assertTrue(output.contains("<TestPackage name=\"run\" runTime=\"3s\" digest=\"\" " +
+ "failed=\"0\" notExecuted=\"0\" timeout=\"0\" omitted=\"0\" pass=\"1\" total=\"1\">"));
+ assertTrue(output.contains(String.format("<TestCase name=\"%s\">", testId.getClassName())));
+
+ final String testCaseTag = String.format(
+ "<Test name=\"%s\" result=\"pass\" />", testId.getTestName());
+ assertTrue(output.contains(testCaseTag));
+ }
+
+ /**
+ * A simple test to ensure expected output is generated for test run with a single failed test.
+ */
+ public void testSingleFail() {
+ Map<String, String> emptyMap = Collections.emptyMap();
+ final TestIdentifier testId = new TestIdentifier("FooTest", "testFoo");
+ final String trace = "this is a trace\nmore trace";
+ mResultReporter.invocationStarted(new BuildInfo());
+ mResultReporter.testRunStarted("run", 1);
+ mResultReporter.testStarted(testId);
+ mResultReporter.testFailed(TestFailure.FAILURE, testId, trace);
+ mResultReporter.testEnded(testId, emptyMap);
+ mResultReporter.testRunEnded(3, emptyMap);
+ mResultReporter.invocationEnded(1);
+ String output = getOutput();
+ System.out.print(getOutput());
+ // TODO: consider doing xml based compare
+ assertTrue(output.contains(
+ "<Summary failed=\"1\" notExecuted=\"0\" timeout=\"0\" omitted=\"0\" pass=\"0\" total=\"1\" />"));
+ final String failureTag =
+ "<FailedScene message=\"this is a trace\">this is a tracemore trace";
+ assertTrue(output.contains(failureTag));
+ }
+
+ /**
+ * Gets the output produced, stripping it of extraneous whitespace characters.
+ */
+ private String getOutput() {
+ String output = mOutputStream.toString();
+ // ignore newlines and tabs whitespace
+ output = output.replaceAll("[\\r\\n\\t]", "");
+ // replace two ws chars with one
+ return output.replaceAll(" ", " ");
+ }
+}
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/targetsetup/CtsSetupTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/targetsetup/CtsSetupTest.java
new file mode 100644
index 0000000..932f3dc
--- /dev/null
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/targetsetup/CtsSetupTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2010 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.targetsetup;
+
+import com.android.ddmlib.Log;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.targetsetup.BuildError;
+import com.android.tradefed.targetsetup.IBuildInfo;
+import com.android.tradefed.targetsetup.IFolderBuildInfo;
+import com.android.tradefed.targetsetup.TargetSetupError;
+
+import org.easymock.EasyMock;
+
+import java.io.File;
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link CtsSetup}.
+ */
+public class CtsSetupTest extends TestCase {
+
+ private static final String LOG_TAG = "CtsSetupTest";
+
+ private CtsSetup mSetup;
+ private ITestDevice mMockDevice;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mSetup = new CtsSetup() {
+ @Override
+ CtsBuildHelper createBuildHelper(File rootDir) {
+ try {
+ return StubCtsBuildHelper.createStubHelper();
+ } catch (IOException e) {
+ Log.e(LOG_TAG, e);
+ fail("failed to create stub helper");
+ return null;
+ }
+ }
+ };
+ mMockDevice = EasyMock.createMock(ITestDevice.class);
+ }
+
+ /**
+ * Test {@link CtsSetup#setUp(ITestDevice, IBuildInfo)} when provided buildInfo is the incorrect
+ * type
+ */
+ public void testSetUp_wrongBuildInfo() throws TargetSetupError, BuildError,
+ DeviceNotAvailableException {
+ try {
+ mSetup.setUp(mMockDevice, EasyMock.createMock(IBuildInfo.class));
+ fail("IllegalArgumentException not thrown");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ /**
+ * Test normal case for {@link CtsSetup#setUp(ITestDevice, IBuildInfo)}
+ */
+ public void testSetUp() throws TargetSetupError, BuildError, DeviceNotAvailableException {
+ IFolderBuildInfo ctsBuild = EasyMock.createMock(IFolderBuildInfo.class);
+ EasyMock.expect(ctsBuild.getRootDir()).andReturn(
+ new File("tmp")).anyTimes();
+ EasyMock.expect(ctsBuild.getBuildId()).andStubReturn(0);
+ EasyMock.expect(
+ mMockDevice.installPackage((File)EasyMock.anyObject(), EasyMock.anyBoolean()))
+ .andReturn(null)
+ .anyTimes();
+ EasyMock.replay(ctsBuild, mMockDevice);
+ mSetup.setUp(mMockDevice, ctsBuild);
+ }
+}
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/targetsetup/StubCtsBuildHelper.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/targetsetup/StubCtsBuildHelper.java
new file mode 100644
index 0000000..53a79be
--- /dev/null
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/targetsetup/StubCtsBuildHelper.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2010 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.targetsetup;
+
+import com.android.tradefed.util.FileUtil;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+/**
+ * Stub implementation of CtsBuildHelper that returns empty files for all methods
+ */
+public class StubCtsBuildHelper extends CtsBuildHelper {
+
+ public static StubCtsBuildHelper createStubHelper() throws IOException {
+ File tmpFolder= FileUtil.createTempDir("ctstmp");
+ File ctsinstall = new File(tmpFolder, CtsBuildHelper.CTS_DIR_NAME);
+ ctsinstall.mkdirs();
+ return new StubCtsBuildHelper(tmpFolder);
+ }
+
+ private StubCtsBuildHelper(File rootDir) throws FileNotFoundException {
+ super(rootDir);
+ }
+
+ @Override
+ public File getTestApp(String appFileName) throws FileNotFoundException {
+ return new File("tmp");
+ }
+
+ @Override
+ public File getTestPlansDir() throws FileNotFoundException {
+ return new File("tmp");
+ }
+
+ @Override
+ public File getTestCasesDir() {
+ return new File("tmp");
+ }
+}
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/JarHostTestTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/JarHostTestTest.java
new file mode 100644
index 0000000..fcd9563
--- /dev/null
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/JarHostTestTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2010 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.testrunner.TestIdentifier;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.result.ITestInvocationListener;
+
+import org.easymock.EasyMock;
+
+import java.net.URL;
+import java.util.Collections;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link JarHostTest}.
+ */
+public class JarHostTestTest extends TestCase {
+
+ private static final String RUN_NAME = "run";
+ private JarHostTest mJarTest;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mJarTest = new JarHostTest() {
+ // mock out the loading from jar
+ @Override
+ Class<?> loadClass(String className, URL[] urls) throws ClassNotFoundException {
+ return MockTest.class;
+ }
+ };
+ }
+
+ public static class MockTest extends TestCase {
+ public MockTest(String name) {
+ super(name);
+ }
+
+ public void testFoo() {
+ }
+ }
+
+ /**
+ * Test normal case for
+ * {@link JarHostTest#run(com.android.tradefed.result.ITestInvocationListener)}.
+ */
+ @SuppressWarnings("unchecked")
+ public void testRun() throws DeviceNotAvailableException {
+ ITestInvocationListener listener = EasyMock.createMock(ITestInvocationListener.class);
+ TestIdentifier expectedTest = new TestIdentifier(MockTest.class.getName(), "testFoo");
+
+ listener.testRunStarted(RUN_NAME, 1);
+ listener.testStarted(expectedTest);
+ listener.testEnded(expectedTest, Collections.EMPTY_MAP);
+ listener.testRunEnded(EasyMock.anyLong(), EasyMock.eq(Collections.EMPTY_MAP));
+
+ EasyMock.replay(listener);
+
+ mJarTest.setRunName(RUN_NAME);
+ mJarTest.run(listener);
+ }
+
+}
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/PlanTestTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/PlanTestTest.java
new file mode 100644
index 0000000..1c2b4b6
--- /dev/null
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/PlanTestTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2010 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.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.util.xml.AbstractXmlParser.ParseException;
+
+import org.easymock.EasyMock;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link PlanTest}.
+ */
+public class PlanTestTest extends TestCase {
+
+ /** the test fixture under test, with all external dependencies mocked out */
+ private PlanTest mPlanTest;
+ private ITestCaseRepo mMockRepo;
+ private IPlanXmlParser mMockPlanParser;
+ private ITestDevice mMockDevice;
+ private ITestInvocationListener mMockListener;
+
+ private static final String PLAN_NAME = "CTS";
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mMockRepo = EasyMock.createMock(ITestCaseRepo.class);
+ mMockPlanParser = EasyMock.createMock(IPlanXmlParser.class);
+ mMockDevice = EasyMock.createMock(ITestDevice.class);
+ mMockListener = EasyMock.createNiceMock(ITestInvocationListener.class);
+
+ mPlanTest = new PlanTest() {
+ @Override
+ ITestCaseRepo createTestCaseRepo() {
+ return mMockRepo;
+ }
+
+ @Override
+ IPlanXmlParser createXmlParser() {
+ return mMockPlanParser;
+ }
+
+ @Override
+ InputStream createXmlStream(File xmlFile) throws FileNotFoundException {
+ // return empty stream, not used
+ return new ByteArrayInputStream(new byte[0]);
+ }
+ };
+ mPlanTest.setDevice(mMockDevice);
+ // not used, but needs to be non-null
+ mPlanTest.setTestCaseDir(new File("tmp"));
+ mPlanTest.setTestPlanDir(new File("tmp"));
+ mPlanTest.setPlanName(PLAN_NAME);
+ }
+
+ /**
+ * Test normal case {@link PlanTest#run(java.util.List)}.
+ * <p/>
+ * Not that interesting of a test in its current form, but sets the stage for testing more
+ * complicated scenarios.
+ */
+ @SuppressWarnings("unchecked")
+ public void testRun() throws DeviceNotAvailableException, ParseException {
+ // expect
+ mMockPlanParser.parse((InputStream)EasyMock.anyObject());
+ Collection<String> uris = new ArrayList<String>(1);
+ uris.add("test-uri");
+ EasyMock.expect(mMockPlanParser.getTestUris()).andReturn(uris);
+
+ IRemoteTest mockTest = EasyMock.createMock(IRemoteTest.class);
+ Collection<IRemoteTest> tests = new ArrayList<IRemoteTest>(1);
+ tests.add(mockTest);
+ EasyMock.expect(mMockRepo.getTests(uris)).andReturn(tests);
+
+ // expect
+ mockTest.run((List<ITestInvocationListener>)EasyMock.anyObject());
+
+ replayMocks();
+ EasyMock.replay(mockTest);
+ mPlanTest.run(mMockListener);
+ verifyMocks();
+ }
+
+ private void replayMocks() {
+ EasyMock.replay(mMockRepo, mMockPlanParser, mMockDevice, mMockListener);
+ }
+
+ private void verifyMocks() {
+ EasyMock.verify(mMockRepo, mMockPlanParser, mMockDevice, mMockListener);
+ }
+}
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/PlanXmlParserTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/PlanXmlParserTest.java
new file mode 100644
index 0000000..803b230
--- /dev/null
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/PlanXmlParserTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2010 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.tradefed.util.xml.AbstractXmlParser.ParseException;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.Iterator;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link PlanXmlParser}.
+ */
+public class PlanXmlParserTest extends TestCase {
+
+ private static final String TEST_URI1 = "foo";
+ private static final String TEST_URI2 = "foo2";
+
+ static final String TEST_DATA =
+ "<TestPlan version=\"1.0\">" +
+ String.format("<Entry uri=\"%s\" />", TEST_URI1) +
+ String.format("<Entry uri=\"%s\" />", TEST_URI2) +
+ "</TestPlan>";
+
+ /**
+ * Simple test for parsing a plan containing two uris
+ */
+ public void testParse() throws ParseException {
+ PlanXmlParser parser = new PlanXmlParser();
+ parser.parse(getStringAsStream(TEST_DATA));
+ assertEquals(2, parser.getTestUris().size());
+ Iterator<String> iter = parser.getTestUris().iterator();
+ // assert uris in order
+ assertEquals(TEST_URI1, iter.next());
+ assertEquals(TEST_URI2, iter.next());
+ }
+
+ private InputStream getStringAsStream(String input) {
+ return new ByteArrayInputStream(input.getBytes());
+ }
+}
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/TestPackageXmlParserTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/TestPackageXmlParserTest.java
new file mode 100644
index 0000000..b24c0e3
--- /dev/null
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/TestPackageXmlParserTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2010 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.testrunner.TestIdentifier;
+import com.android.tradefed.util.xml.AbstractXmlParser.ParseException;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.Iterator;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link TestPackageXmlParser}.
+ */
+public class TestPackageXmlParserTest extends TestCase {
+
+ private static String INSTR_TEST_DATA =
+ "<TestPackage AndroidFramework=\"Android 1.0\" appNameSpace=\"com.example\" " +
+ "appPackageName=\"android.example\" name=\"CtsExampleTestCases\" " +
+ "runner=\"android.test.InstrumentationTestRunner\" version=\"1.0\">" +
+ "</TestPackage>";
+
+ private static String HOST_TEST_DATA =
+ "<TestPackage hostSideOnly=\"true\" >\n" +
+ " <TestSuite name=\"com\" >\n" +
+ " <TestSuite name=\"example\" >\n" +
+ " <TestCase name=\"ExampleTest\" >\n" +
+ " <Test name=\"testFoo\" />\n" +
+ " <Test name=\"testFoo2\" />\n" +
+ " </TestCase>\n" +
+ " </TestSuite>\n" +
+ " <TestSuite name=\"example2\" >\n" +
+ " <TestCase name=\"Example2Test\" >\n" +
+ " <Test name=\"testFoo\" />\n" +
+ " </TestCase>\n" +
+ " </TestSuite>\n" +
+ " </TestSuite>\n" +
+ "</TestPackage>";
+
+ private static String BAD_HOST_TEST_DATA =
+ "<TestPackage hostSideOnly=\"blah\" >" +
+ "</TestPackage>";
+
+ private static String NO_TEST_DATA =
+ "<invalid />";
+
+ /**
+ * Test parsing test case xml containing an instrumentation test definition.
+ */
+ public void testParse_instrPackage() throws ParseException {
+ TestPackageXmlParser parser = new TestPackageXmlParser();
+ parser.parse(getStringAsStream(INSTR_TEST_DATA));
+ TestPackageDef def = parser.getTestPackageDef();
+ assertEquals("com.example", def.getAppNameSpace());
+ assertEquals("android.example", def.getUri());
+ assertEquals("android.test.InstrumentationTestRunner", def.getRunner());
+ }
+
+ /**
+ * Test parsing test case xml containing an host test attribute and test data.
+ */
+ public void testParse_hostTest() throws ParseException {
+ TestPackageXmlParser parser = new TestPackageXmlParser();
+ parser.parse(getStringAsStream(HOST_TEST_DATA));
+ TestPackageDef def = parser.getTestPackageDef();
+ assertTrue(def.isHostSideTest());
+ assertEquals(3, def.getTests().size());
+ Iterator<TestIdentifier> iterator = def.getTests().iterator();
+
+ TestIdentifier firstTest = iterator.next();
+ assertEquals("com.example.ExampleTest", firstTest.getClassName());
+ assertEquals("testFoo", firstTest.getTestName());
+
+ TestIdentifier secondTest = iterator.next();
+ assertEquals("com.example.ExampleTest", secondTest.getClassName());
+ assertEquals("testFoo2", secondTest.getTestName());
+
+ TestIdentifier thirdTest = iterator.next();
+ assertEquals("com.example2.Example2Test", thirdTest.getClassName());
+ assertEquals("testFoo", thirdTest.getTestName());
+ }
+
+ /**
+ * Test parsing test case xml containing an invalid host test attribute.
+ */
+ public void testParse_badHostTest() throws ParseException {
+ TestPackageXmlParser parser = new TestPackageXmlParser();
+ parser.parse(getStringAsStream(BAD_HOST_TEST_DATA));
+ TestPackageDef def = parser.getTestPackageDef();
+ assertFalse(def.isHostSideTest());
+ }
+
+ /**
+ * Test parsing a test case xml with no test package data.
+ */
+ public void testParse_noData() throws ParseException {
+ TestPackageXmlParser parser = new TestPackageXmlParser();
+ parser.parse(getStringAsStream(NO_TEST_DATA));
+ assertNull(parser.getTestPackageDef());
+ }
+
+ private InputStream getStringAsStream(String input) {
+ return new ByteArrayInputStream(input.getBytes());
+ }
+}
diff --git a/tools/utils/buildCts.py b/tools/utils/buildCts.py
index 86d870e..7d4b6e0 100755
--- a/tools/utils/buildCts.py
+++ b/tools/utils/buildCts.py
@@ -94,9 +94,9 @@
source_path = [
'frameworks/base/core/java', # android test classes
'frameworks/base/test-runner/src', # test runner
- 'dalvik/libcore/junit/src/main/java', # junit classes
+ 'libcore/junit/src/main/java', # junit classes
'development/tools/hosttestlib/src', # hosttestlib TestCase extensions
- 'dalvik/libcore/dalvik/src/main/java', # test annotations
+ 'libcore/dalvik/src/main/java', # test annotations
'cts/libs/annotation/src', # cts annotations
'cts/tests/src', # cts test stubs
source_root # the source for this package
diff --git a/tools/utils/startcts b/tools/utils/startcts
index af9d503..c648125 100755
--- a/tools/utils/startcts
+++ b/tools/utils/startcts
@@ -49,7 +49,7 @@
checkDir ${CTS_ROOT} "Error: Cannot locate CTS in \"${CTS_DIR}\". Please check your configuration in $0"
checkDir ${SDK_ROOT} "Error: Cannot locate SDK installation in \"${SDK_ROOT}\". Please check your configuration in $0"
-DDM_LIB=${SDK_ROOT}/tools/lib/ddmlib.jar
+DDM_LIB=${CTS_ROOT}/tools/ddmlib-prebuilt.jar
CTS_LIB=${CTS_ROOT}/tools/cts.jar
JUNIT_LIB=${CTS_ROOT}/tools/junit.jar
HOSTTEST_LIB=${CTS_ROOT}/tools/hosttestlib.jar
diff --git a/tools/vm-tests/src/dot/junit/opcodes/invoke_super/Test_invoke_super.java b/tools/vm-tests/src/dot/junit/opcodes/invoke_super/Test_invoke_super.java
index a2fd2d8..6efac8b 100644
--- a/tools/vm-tests/src/dot/junit/opcodes/invoke_super/Test_invoke_super.java
+++ b/tools/vm-tests/src/dot/junit/opcodes/invoke_super/Test_invoke_super.java
@@ -292,6 +292,21 @@
}
/**
+ * @constraint n/a
+ * @title invoke-super shall be used to invoke private methods
+ */
+ public void testVFE16() {
+ //@uses dot.junit.opcodes.invoke_super.d.T_invoke_super_13
+ //@uses dot.junit.opcodes.invoke_super.d.TSuper
+ try {
+ Class.forName("dot.junit.opcodes.invoke_super.d.T_invoke_super_13");
+ fail("expected a verification exception");
+ } catch (Throwable t) {
+ DxUtil.checkVerifyException(t);
+ }
+ }
+
+ /**
* @constraint A23
* @title number of registers
*/
diff --git a/tools/vm-tests/src/dot/junit/opcodes/invoke_super_range/Test_invoke_super_range.java b/tools/vm-tests/src/dot/junit/opcodes/invoke_super_range/Test_invoke_super_range.java
index 7bee936..d65b8d4 100644
--- a/tools/vm-tests/src/dot/junit/opcodes/invoke_super_range/Test_invoke_super_range.java
+++ b/tools/vm-tests/src/dot/junit/opcodes/invoke_super_range/Test_invoke_super_range.java
@@ -292,6 +292,21 @@
}
/**
+ * @constraint n/a
+ * @title invoke-super/range shall be used to invoke private methods
+ */
+ public void testVFE16() {
+ //@uses dot.junit.opcodes.invoke_super_range.d.T_invoke_super_range_13
+ //@uses dot.junit.opcodes.invoke_super_range.d.TSuper
+ try {
+ Class.forName("dot.junit.opcodes.invoke_super_range.d.T_invoke_super_range_13");
+ fail("expected a verification exception");
+ } catch (Throwable t) {
+ DxUtil.checkVerifyException(t);
+ }
+ }
+
+ /**
* @constraint A23
* @title number of registers
*/
diff --git a/tools/vm-tests/src/dot/junit/opcodes/invoke_virtual/Test_invoke_virtual.java b/tools/vm-tests/src/dot/junit/opcodes/invoke_virtual/Test_invoke_virtual.java
index 70e9f9e..6e41ec1 100644
--- a/tools/vm-tests/src/dot/junit/opcodes/invoke_virtual/Test_invoke_virtual.java
+++ b/tools/vm-tests/src/dot/junit/opcodes/invoke_virtual/Test_invoke_virtual.java
@@ -286,6 +286,19 @@
}
/**
+ * @constraint n/a
+ * @title invoke-virtual shall be used to invoke private methods
+ */
+ public void testVFE16() {
+ try {
+ Class.forName("dot.junit.opcodes.invoke_virtual.d.T_invoke_virtual_13");
+ fail("expected a verification exception");
+ } catch (Throwable t) {
+ DxUtil.checkVerifyException(t);
+ }
+ }
+
+ /**
* @constraint A23
* @title number of registers
*/
diff --git a/tools/vm-tests/src/dot/junit/opcodes/invoke_virtual_range/Test_invoke_virtual_range.java b/tools/vm-tests/src/dot/junit/opcodes/invoke_virtual_range/Test_invoke_virtual_range.java
index 4f91ba8..2368dc3 100644
--- a/tools/vm-tests/src/dot/junit/opcodes/invoke_virtual_range/Test_invoke_virtual_range.java
+++ b/tools/vm-tests/src/dot/junit/opcodes/invoke_virtual_range/Test_invoke_virtual_range.java
@@ -294,6 +294,19 @@
}
/**
+ * @constraint n/a
+ * @title invoke-virtual/range shall be used to invoke private methods
+ */
+ public void testVFE16() {
+ try {
+ Class.forName("dot.junit.opcodes.invoke_virtual_range.d.T_invoke_virtual_range_13");
+ fail("expected a verification exception");
+ } catch (Throwable t) {
+ DxUtil.checkVerifyException(t);
+ }
+ }
+
+ /**
* @constraint A23
* @title number of registers
*/