Merge "Add a CTS case to catch non-recycleable view types bug" into mnc-dev
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index f683840..9021921 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -62,7 +62,9 @@
CtsKeySetSharedUserSigningBUpgradeB \
CtsKeySetSigningABadUpgradeB \
CtsKeySetSigningCBadAUpgradeAB \
- CtsKeySetSigningANoDefUpgradeB
+ CtsKeySetSigningANoDefUpgradeB \
+ CtsKeySetSigningAUpgradeEcA \
+ CtsKeySetSigningEcAUpgradeA
cts_support_packages := \
CtsAccelerationTestStubs \
diff --git a/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-dsa-a.pk8 b/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-dsa-a.pk8
new file mode 100644
index 0000000..ac0b0c1
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-dsa-a.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-ec-a.pk8 b/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-ec-a.pk8
new file mode 100644
index 0000000..ec27be1
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-ec-a.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-ec-a.x509.pem b/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-ec-a.x509.pem
new file mode 100644
index 0000000..183691d
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-ec-a.x509.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBejCCAR+gAwIBAgIJAMsY4Fz5jr/IMAoGCCqGSM49BAMCMBkxFzAVBgNVBAMM
+DnVuaXRfdGVzdF9lY19hMB4XDTE1MDYwMTIxNDU1M1oXDTQyMTAxNzIxNDU1M1ow
+GTEXMBUGA1UEAwwOdW5pdF90ZXN0X2VjX2EwWTATBgcqhkjOPQIBBggqhkjOPQMB
+BwNCAAR8Q+7lg4KSOs2Be0XhFwlFCsiCCIh3iX2t6fE+V/MD+QBT1265hIyBKEH/
+oAsTpLy8FdGKLC0x+TwuCedui0SBo1AwTjAdBgNVHQ4EFgQUX4h7gPTgwQXorm0H
+7R12wN2yNrwwHwYDVR0jBBgwFoAUX4h7gPTgwQXorm0H7R12wN2yNrwwDAYDVR0T
+BAUwAwEB/zAKBggqhkjOPQQDAgNJADBGAiEA5kHO4aK20dwt81mCABAywD7Y6V1O
+vqoff9yIx3USW8oCIQDTzo8tbHuPc+i3vBsb5Uo1+4BE/pcOe/je6PGlRHG8rg==
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/KeySetHostTest.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/KeySetHostTest.java
index 7f3737d..9637a6c 100644
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/KeySetHostTest.java
+++ b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/KeySetHostTest.java
@@ -76,6 +76,10 @@
"CtsKeySetSigningCBadAUpgradeAB.apk";
private static final String A_SIGNED_NO_B_B_UPGRADE =
"CtsKeySetSigningANoDefUpgradeB.apk";
+ private static final String A_SIGNED_EC_A_UPGRADE =
+ "CtsKeySetSigningAUpgradeEcA.apk";
+ private static final String EC_A_SIGNED_A_UPGRADE =
+ "CtsKeySetSigningEcAUpgradeA.apk";
/* package which defines the KEYSET_PERM_NAME signature permission */
private static final String KEYSET_PERM_DEF_PKG =
@@ -486,4 +490,26 @@
assertNotNull("Installation of apk with upgrade key referring to a bad public key succeeded!",
installResult);
}
+
+ /*
+ * Check if an apk signed by RSA pub key can upgrade to apk signed by EC key.
+ */
+ public void testUpgradeKSRsaToEC() throws Exception {
+ String installResult = testPackageUpgrade(KEYSET_PKG, A_SIGNED_EC_A_UPGRADE,
+ EC_A_SIGNED_A_UPGRADE);
+ assertNull(String.format("failed to upgrade keyset app from one signed by RSA key"
+ + "to version signed by EC upgrade-key-set, Reason: %s", installResult),
+ installResult);
+ }
+
+ /*
+ * Check if an apk signed by EC pub key can upgrade to apk signed by RSA key.
+ */
+ public void testUpgradeKSECToRSA() throws Exception {
+ String installResult = testPackageUpgrade(KEYSET_PKG, EC_A_SIGNED_A_UPGRADE,
+ A_SIGNED_EC_A_UPGRADE);
+ assertNull(String.format("failed to upgrade keyset app from one signed by EC key"
+ + "to version signed by RSA upgrade-key-set, Reason: %s", installResult),
+ installResult);
+ }
}
diff --git a/hostsidetests/appsecurity/test-apps/DocumentProvider/src/com/android/cts/documentprovider/MyDocumentsProvider.java b/hostsidetests/appsecurity/test-apps/DocumentProvider/src/com/android/cts/documentprovider/MyDocumentsProvider.java
index fb8993c..14f215c 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentProvider/src/com/android/cts/documentprovider/MyDocumentsProvider.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentProvider/src/com/android/cts/documentprovider/MyDocumentsProvider.java
@@ -239,13 +239,16 @@
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
- try {
- final InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(
- pipe[0]);
- doc.contents = readFullyNoClose(is);
- is.close();
- } catch (IOException e) {
- Log.w(TAG, "Failed to stream", e);
+ synchronized (doc) {
+ try {
+ final InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(
+ pipe[0]);
+ doc.contents = readFullyNoClose(is);
+ is.close();
+ doc.notifyAll();
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to stream", e);
+ }
}
return null;
}
@@ -255,13 +258,20 @@
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
- try {
- final OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(
- pipe[1]);
- os.write(doc.contents);
- os.close();
- } catch (IOException e) {
- Log.w(TAG, "Failed to stream", e);
+ synchronized (doc) {
+ try {
+ final OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(
+ pipe[1]);
+ while (doc.contents == null) {
+ doc.wait();
+ }
+ os.write(doc.contents);
+ os.close();
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to stream", e);
+ } catch (InterruptedException e) {
+ Log.w(TAG, "Interuppted", e);
+ }
}
return null;
}
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk
index 4d441de..79d053b 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk
@@ -37,6 +37,18 @@
include $(BUILD_CTS_SUPPORT_PACKAGE)
+#apks signed by cts-keyset-test-ec-a
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_PACKAGE_NAME := CtsKeySetSigningEcAUpgradeA
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-ec-a
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
+
#apks signed by cts-keyset-test-a and cts-keyset-test-b
include $(CLEAR_VARS)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uEcA/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uEcA/Android.mk
new file mode 100644
index 0000000..3d0109a
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/keysets/uEcA/Android.mk
@@ -0,0 +1,27 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+#apks signed by cts-keyset-test-a
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_PACKAGE_NAME := CtsKeySetSigningAUpgradeEcA
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uEcA/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/keysets/uEcA/AndroidManifest.xml
new file mode 100644
index 0000000..a84704a
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/keysets/uEcA/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.keysets">
+ <application android:hasCode="false">
+ </application>
+ <key-sets>
+ <key-set android:name="EcA" >
+ <public-key android:name="keyEcA"
+ android:value="MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfEPu5YOCkjrNgXtF4RcJRQrIggiId4l9renxPlfzA/kAU9duuYSMgShB/6ALE6S8vBXRiiwtMfk8LgnnbotEgQ=="/>
+ </key-set>
+ <upgrade-key-set android:name="EcA"/>
+ </key-sets>
+</manifest>
diff --git a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
index b11248a..71bf6cf 100644
--- a/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
+++ b/tests/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
@@ -313,12 +313,14 @@
// create the notification to send
final int notificationId = 1;
- final Notification notification = new Notification();
- notification.icon = android.R.drawable.stat_notify_call_mute;
- notification.contentIntent = PendingIntent.getActivity(getActivity(), 0, new Intent(),
- PendingIntent.FLAG_CANCEL_CURRENT);
- notification.tickerText = message;
- notification.setLatestEventInfo(getActivity(), "", "", notification.contentIntent);
+ final Notification notification = new Notification.Builder(getActivity())
+ .setSmallIcon(android.R.drawable.stat_notify_call_mute)
+ .setContentIntent(PendingIntent.getActivity(getActivity(), 0, new Intent(),
+ PendingIntent.FLAG_CANCEL_CURRENT))
+ .setTicker(message)
+ .setContentTitle("")
+ .setContentText("")
+ .build();
// create and populate the expected event
final AccessibilityEvent expected = AccessibilityEvent.obtain();
diff --git a/tests/tests/app/AndroidManifest.xml b/tests/tests/app/AndroidManifest.xml
index 8e17396..d05648c 100644
--- a/tests/tests/app/AndroidManifest.xml
+++ b/tests/tests/app/AndroidManifest.xml
@@ -18,6 +18,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cts.app">
+ <uses-sdk android:minSdkVersion="11" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.BODY_SENSORS" />
<application>
diff --git a/tests/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/tests/app/src/android/app/cts/NotificationManagerTest.java
index 23dac25..5781442 100644
--- a/tests/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -100,9 +100,6 @@
}
private void sendNotification(final int id, final int icon) {
- final Notification notification = new Notification(
- icon, "No intent", System.currentTimeMillis());
-
final Intent intent = new Intent(Intent.ACTION_MAIN, Threads.CONTENT_URI);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP
@@ -110,8 +107,13 @@
intent.setAction(Intent.ACTION_MAIN);
final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
- notification.setLatestEventInfo(mContext, "notify#" + id, "This is #" + id
- + "notification ", pendingIntent);
+ final Notification notification = new Notification.Builder(mContext)
+ .setSmallIcon(icon)
+ .setWhen(System.currentTimeMillis())
+ .setContentTitle("notify#" + id)
+ .setContentText("This is #" + id + "notification ")
+ .setContentIntent(pendingIntent)
+ .build();
mNotificationManager.notify(id, notification);
StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
diff --git a/tests/tests/app/src/android/app/cts/NotificationTest.java b/tests/tests/app/src/android/app/cts/NotificationTest.java
index c2f62c3..614d7f2 100644
--- a/tests/tests/app/src/android/app/cts/NotificationTest.java
+++ b/tests/tests/app/src/android/app/cts/NotificationTest.java
@@ -150,6 +150,22 @@
assertNull(result.sound);
}
+ public void testBuilder() {
+ final Intent intent = new Intent();
+ final PendingIntent contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+ mNotification = new Notification.Builder(mContext)
+ .setSmallIcon(1)
+ .setContentTitle(CONTENT_TITLE)
+ .setContentText(CONTENT_TEXT)
+ .setContentIntent(contentIntent)
+ .build();
+ assertEquals(CONTENT_TEXT, mNotification.extras.getString(Notification.EXTRA_TEXT));
+ assertEquals(CONTENT_TITLE, mNotification.extras.getString(Notification.EXTRA_TITLE));
+ assertEquals(1, mNotification.icon);
+ assertEquals(contentIntent, mNotification.contentIntent);
+ assertNotNull(mNotification.contentView);
+ }
+
public void testSetLatestEventInfo() {
mNotification = new Notification();
mNotification.icon = 1;
diff --git a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
index 629e85e..8d96d91 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
@@ -1268,7 +1268,7 @@
try {
// start < context start
- p.getOffsetForAdvance(string, 1, string.length(), 0, string.length(), false, 0.0f);
+ p.getOffsetForAdvance(string, 0, string.length(), 1, string.length(), false, 0.0f);
fail("Should throw an IndexOutOfBoundsException.");
} catch (IndexOutOfBoundsException e) {
} catch (Exception e) {
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
index 452f0d0..0913152 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
@@ -16,6 +16,7 @@
package android.graphics.drawable.cts;
+import android.view.Gravity;
import com.android.cts.graphics.R;
import org.xmlpull.v1.XmlPullParserException;
@@ -799,6 +800,611 @@
assertEquals(1, constantState.getChangingConfigurations());
}
+ @SuppressWarnings("deprecation")
+ public void testAddLayer() {
+ Drawable[] array = new Drawable[] { new BitmapDrawable(), new ColorDrawable(Color.BLUE) };
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+ BitmapDrawable newDrawable = new BitmapDrawable();
+ int index = layerDrawable.addLayer(newDrawable);
+
+ final int numLayers = layerDrawable.getNumberOfLayers();
+ assertEquals(index, numLayers - 1);
+ assertEquals(newDrawable, layerDrawable.getDrawable(index));
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testGetDrawable() {
+ Drawable[] array = new Drawable[] { new BitmapDrawable(), new ColorDrawable(Color.BLUE) };
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ final int numLayers = layerDrawable.getNumberOfLayers();
+ assertEquals(array[0], layerDrawable.getDrawable(0));
+ assertEquals(array[1], layerDrawable.getDrawable(1));
+ try {
+ assertEquals(null, layerDrawable.getDrawable(2));
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testFindIndexByLayerId() {
+ Drawable[] array = new Drawable[] { new BitmapDrawable(), new ColorDrawable(Color.BLUE) };
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ layerDrawable.setId(0, 10);
+ layerDrawable.setId(1, 20);
+
+ assertEquals(0, layerDrawable.findIndexByLayerId(10));
+ assertEquals(1, layerDrawable.findIndexByLayerId(20));
+ assertEquals(-1, layerDrawable.findIndexByLayerId(30));
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testSetDrawable() {
+ Drawable[] array = new Drawable[]{new BitmapDrawable(), new ColorDrawable(Color.BLUE)};
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+ BitmapDrawable newBitmapDrawable = new BitmapDrawable();
+ ColorDrawable newColorDrawable = new ColorDrawable(Color.GREEN);
+ layerDrawable.setDrawable(0, newColorDrawable);
+ layerDrawable.setDrawable(1, newBitmapDrawable);
+
+ final int numLayers = layerDrawable.getNumberOfLayers();
+ assertEquals(2, numLayers);
+ assertEquals(newColorDrawable, layerDrawable.getDrawable(0));
+ assertEquals(newBitmapDrawable, layerDrawable.getDrawable(1));
+ try {
+ assertEquals(null, layerDrawable.getDrawable(2));
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testGetLeftPadding() {
+ Drawable[] array = new Drawable[]{new BitmapDrawable()};
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+ layerDrawable.setPadding(10, 11, 20, 21);
+
+ assertEquals(10, layerDrawable.getLeftPadding());
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testGetTopPadding() {
+ Drawable[] array = new Drawable[]{new BitmapDrawable()};
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+ layerDrawable.setPadding(10, 11, 20, 21);
+
+ assertEquals(11, layerDrawable.getTopPadding());
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testGetRightPadding() {
+ Drawable[] array = new Drawable[]{new BitmapDrawable()};
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+ layerDrawable.setPadding(10, 11, 20, 21);
+
+ assertEquals(20, layerDrawable.getRightPadding());
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testGetBottomPadding() {
+ Drawable[] array = new Drawable[]{new BitmapDrawable()};
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+ layerDrawable.setPadding(10, 11, 20, 21);
+
+ assertEquals(21, layerDrawable.getBottomPadding());
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testGetStartPadding() {
+ Drawable[] array = new Drawable[]{new BitmapDrawable()};
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+ layerDrawable.setPadding(10, 11, 20, 21);
+
+ assertEquals(-1, layerDrawable.getStartPadding());
+ layerDrawable.setPaddingRelative(10, 11, 20, 21);
+ assertEquals(10, layerDrawable.getStartPadding());
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testGetEndPadding() {
+ Drawable[] array = new Drawable[]{new BitmapDrawable()};
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+ layerDrawable.setPadding(10, 11, 20, 21);
+
+ assertEquals(-1, layerDrawable.getEndPadding());
+ layerDrawable.setPaddingRelative(10, 11, 20, 21);
+ assertEquals(20, layerDrawable.getEndPadding());
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testSetPadding() {
+ Drawable[] array = new Drawable[]{new BitmapDrawable()};
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+ layerDrawable.setPadding(10, 11, 20, 21);
+
+ assertEquals(10, layerDrawable.getLeftPadding());
+ assertEquals(11, layerDrawable.getTopPadding());
+ assertEquals(20, layerDrawable.getRightPadding());
+ assertEquals(21, layerDrawable.getBottomPadding());
+ assertEquals(-1, layerDrawable.getStartPadding());
+ assertEquals(-1, layerDrawable.getEndPadding());
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testSetPaddingRelative() {
+ Drawable[] array = new Drawable[]{new BitmapDrawable()};
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+ layerDrawable.setPaddingRelative(10, 11, 20, 21);
+
+ assertEquals(10, layerDrawable.getStartPadding());
+ assertEquals(11, layerDrawable.getTopPadding());
+ assertEquals(20, layerDrawable.getEndPadding());
+ assertEquals(21, layerDrawable.getBottomPadding());
+ assertEquals(-1, layerDrawable.getLeftPadding());
+ assertEquals(-1, layerDrawable.getRightPadding());
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testSetLayerGravity() {
+ Drawable[] array = new Drawable[]{new BitmapDrawable(), new ColorDrawable(Color.BLUE)};
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ layerDrawable.setLayerGravity(0, Gravity.CENTER);
+ layerDrawable.setLayerGravity(1, Gravity.NO_GRAVITY);
+
+ try {
+ layerDrawable.setLayerGravity(2, Gravity.TOP);
+ fail("Should throw ArrayIndexOutOfBoundsException");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+ assertEquals(Gravity.CENTER, layerDrawable.getLayerGravity(0));
+ assertEquals(Gravity.NO_GRAVITY, layerDrawable.getLayerGravity(1));
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testGetLayerGravity() {
+ Drawable[] array = new Drawable[]{new BitmapDrawable(), new ColorDrawable(Color.BLUE)};
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ layerDrawable.setLayerGravity(0, Gravity.CENTER);
+ layerDrawable.setLayerGravity(1, Gravity.NO_GRAVITY);
+
+ assertEquals(Gravity.CENTER, layerDrawable.getLayerGravity(0));
+ assertEquals(Gravity.NO_GRAVITY, layerDrawable.getLayerGravity(1));
+ try {
+ layerDrawable.getLayerGravity(2);
+ fail("Should throw ArrayIndexOutOfBoundsException");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testSetLayerWidth() {
+ Drawable[] array = new Drawable[]{new BitmapDrawable(), new ColorDrawable(Color.BLUE)};
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ layerDrawable.setLayerWidth(0, 100);
+ layerDrawable.setLayerWidth(1, 200);
+
+ try {
+ layerDrawable.setLayerWidth(2, 300);
+ fail("Should throw ArrayIndexOutOfBoundsException");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+ assertEquals(100, layerDrawable.getLayerWidth(0));
+ assertEquals(200, layerDrawable.getLayerWidth(1));
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testGetLayerWidth() {
+ Drawable[] array = new Drawable[]{new BitmapDrawable(), new ColorDrawable(Color.BLUE)};
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ layerDrawable.setLayerWidth(0, 100);
+ layerDrawable.setLayerWidth(1, 200);
+
+ assertEquals(100, layerDrawable.getLayerWidth(0));
+ assertEquals(200, layerDrawable.getLayerWidth(1));
+ try {
+ layerDrawable.getLayerWidth(2);
+ fail("Should throw ArrayIndexOutOfBoundsException");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testSetLayerHeight() {
+ Drawable[] array = new Drawable[]{new BitmapDrawable(), new ColorDrawable(Color.BLUE)};
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ layerDrawable.setLayerHeight(0, 100);
+ layerDrawable.setLayerHeight(1, 200);
+
+ try {
+ layerDrawable.setLayerHeight(2, 300);
+ fail("Should throw ArrayIndexOutOfBoundsException");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+ assertEquals(100, layerDrawable.getLayerHeight(0));
+ assertEquals(200, layerDrawable.getLayerHeight(1));
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testGetLayerHeight() {
+ Drawable[] array = new Drawable[]{new BitmapDrawable(), new ColorDrawable(Color.BLUE)};
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ layerDrawable.setLayerHeight(0, 100);
+ layerDrawable.setLayerHeight(1, 200);
+
+ assertEquals(100, layerDrawable.getLayerHeight(0));
+ assertEquals(200, layerDrawable.getLayerHeight(1));
+ try {
+ layerDrawable.getLayerHeight(2);
+ fail("Should throw ArrayIndexOutOfBoundsException");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testSetLayerSize() {
+ Drawable[] array = new Drawable[]{new BitmapDrawable(), new ColorDrawable(Color.BLUE)};
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ layerDrawable.setLayerSize(0, 100, 200);
+ layerDrawable.setLayerSize(1, 300, 400);
+
+ try {
+ layerDrawable.setLayerSize(2, 500, 600);
+ fail("Should throw ArrayIndexOutOfBoundsException");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+ assertEquals(100, layerDrawable.getLayerWidth(0));
+ assertEquals(200, layerDrawable.getLayerHeight(0));
+ assertEquals(300, layerDrawable.getLayerWidth(1));
+ assertEquals(400, layerDrawable.getLayerHeight(1));
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testSetLayerInsetRelative() {
+ Drawable[] array = new Drawable[] { new BitmapDrawable(), new ColorDrawable(Color.BLUE) };
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ // set inset for layer 0
+ int start = 10;
+ int top = 20;
+ int end = 30;
+ int bottom = 40;
+ layerDrawable.setLayerInsetRelative(0, start, top, end, bottom);
+ assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + start + end,
+ layerDrawable.getIntrinsicWidth());
+ assertEquals(layerDrawable.getDrawable(0).getIntrinsicHeight() + top + bottom,
+ layerDrawable.getIntrinsicHeight());
+ assertEquals(10, layerDrawable.getLayerInsetStart(0));
+ assertEquals(20, layerDrawable.getLayerInsetTop(0));
+ assertEquals(30, layerDrawable.getLayerInsetEnd(0));
+ assertEquals(40, layerDrawable.getLayerInsetBottom(0));
+ assertEquals(0, layerDrawable.getLayerInsetLeft(0));
+ assertEquals(0, layerDrawable.getLayerInsetRight(0));
+
+ // set bigger inset for layer 1
+ start += 10;
+ top += 10;
+ end += 10;
+ bottom += 10;
+ layerDrawable.setLayerInsetRelative(1, start, top, end, bottom);
+ assertEquals(layerDrawable.getDrawable(1).getIntrinsicWidth() + start + end,
+ layerDrawable.getIntrinsicWidth());
+ assertEquals(layerDrawable.getDrawable(1).getIntrinsicHeight() + top + bottom,
+ layerDrawable.getIntrinsicHeight());
+
+
+ try {
+ layerDrawable.setLayerInsetRelative(-1, start, top, end, bottom);
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testSetLayerInsetLeft() {
+ Drawable[] array = new Drawable[] { new BitmapDrawable() };
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ // set inset for layer 0
+ int left = 10;
+ int top = 20;
+ int right = 30;
+ int bottom = 40;
+ layerDrawable.setLayerInset(0, left, top, right, bottom);
+ assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + left + right,
+ layerDrawable.getIntrinsicWidth());
+ left += 5;
+ layerDrawable.setLayerInsetLeft(0, left);
+ assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + left + right,
+ layerDrawable.getIntrinsicWidth());
+ assertEquals(left, layerDrawable.getLayerInsetLeft(0));
+
+ try {
+ layerDrawable.setLayerInsetLeft(1, left);
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testGetLayerInsetLeft() {
+ Drawable[] array = new Drawable[] { new BitmapDrawable() };
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ // set inset for layer 0
+ int left = 10;
+ int top = 20;
+ int right = 30;
+ int bottom = 40;
+ layerDrawable.setLayerInset(0, left, top, right, bottom);
+ assertEquals(left, layerDrawable.getLayerInsetLeft(0));
+ left += 5;
+ layerDrawable.setLayerInsetLeft(0, left);
+ assertEquals(left, layerDrawable.getLayerInsetLeft(0));
+
+ try {
+ layerDrawable.getLayerInsetLeft(1);
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testSetLayerInsetTop() {
+ Drawable[] array = new Drawable[] { new BitmapDrawable() };
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ // set inset for layer 0
+ int left = 10;
+ int top = 20;
+ int right = 30;
+ int bottom = 40;
+ layerDrawable.setLayerInset(0, left, top, right, bottom);
+ assertEquals(layerDrawable.getDrawable(0).getIntrinsicHeight() + top + bottom,
+ layerDrawable.getIntrinsicHeight());
+ top += 5;
+ layerDrawable.setLayerInsetTop(0, top);
+ assertEquals(layerDrawable.getDrawable(0).getIntrinsicHeight() + top + bottom,
+ layerDrawable.getIntrinsicHeight());
+ assertEquals(top, layerDrawable.getLayerInsetTop(0));
+
+ try {
+ layerDrawable.setLayerInsetTop(1, top);
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testGetLayerInsetTop() {
+ Drawable[] array = new Drawable[] { new BitmapDrawable() };
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ // set inset for layer 0
+ int left = 10;
+ int top = 20;
+ int right = 30;
+ int bottom = 40;
+ layerDrawable.setLayerInset(0, left, top, right, bottom);
+ assertEquals(top, layerDrawable.getLayerInsetTop(0));
+ top += 5;
+ layerDrawable.setLayerInsetTop(0, top);
+ assertEquals(top, layerDrawable.getLayerInsetTop(0));
+
+ try {
+ layerDrawable.getLayerInsetTop(1);
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testSetLayerInsetRight() {
+ Drawable[] array = new Drawable[] { new BitmapDrawable() };
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ // set inset for layer 0
+ int left = 10;
+ int top = 20;
+ int right = 30;
+ int bottom = 40;
+ layerDrawable.setLayerInset(0, left, top, right, bottom);
+ assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + left + right,
+ layerDrawable.getIntrinsicWidth());
+ right += 5;
+ layerDrawable.setLayerInsetRight(0, right);
+ assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + left + right,
+ layerDrawable.getIntrinsicWidth());
+ assertEquals(right, layerDrawable.getLayerInsetRight(0));
+
+ try {
+ layerDrawable.setLayerInsetRight(1, right);
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testGetLayerInsetRight() {
+ Drawable[] array = new Drawable[] { new BitmapDrawable() };
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ // set inset for layer 0
+ int left = 10;
+ int top = 20;
+ int right = 30;
+ int bottom = 40;
+ layerDrawable.setLayerInset(0, left, top, right, bottom);
+ assertEquals(right, layerDrawable.getLayerInsetRight(0));
+ right += 5;
+ layerDrawable.setLayerInsetRight(0, right);
+ assertEquals(right, layerDrawable.getLayerInsetRight(0));
+
+ try {
+ layerDrawable.getLayerInsetRight(1);
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testSetLayerInsetBottom() {
+ Drawable[] array = new Drawable[] { new BitmapDrawable() };
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ // set inset for layer 0
+ int left = 10;
+ int top = 20;
+ int right = 30;
+ int bottom = 40;
+ layerDrawable.setLayerInset(0, left, top, right, bottom);
+ assertEquals(layerDrawable.getDrawable(0).getIntrinsicHeight() + top + bottom,
+ layerDrawable.getIntrinsicHeight());
+ bottom += 5;
+ layerDrawable.setLayerInsetBottom(0, bottom);
+ assertEquals(layerDrawable.getDrawable(0).getIntrinsicHeight() + top + bottom,
+ layerDrawable.getIntrinsicHeight());
+ assertEquals(bottom, layerDrawable.getLayerInsetBottom(0));
+
+ try {
+ layerDrawable.setLayerInsetBottom(1, bottom);
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testGetLayerInsetBottom() {
+ Drawable[] array = new Drawable[] { new BitmapDrawable() };
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ // set inset for layer 0
+ int left = 10;
+ int top = 20;
+ int right = 30;
+ int bottom = 40;
+ layerDrawable.setLayerInset(0, left, top, right, bottom);
+ assertEquals(bottom, layerDrawable.getLayerInsetBottom(0));
+ bottom += 5;
+ layerDrawable.setLayerInsetBottom(0, bottom);
+ assertEquals(bottom, layerDrawable.getLayerInsetBottom(0));
+
+ try {
+ layerDrawable.getLayerInsetBottom(1);
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testSetLayerInsetStart() {
+ Drawable[] array = new Drawable[] { new BitmapDrawable() };
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ // set inset for layer 0
+ int start = 10;
+ int top = 20;
+ int end = 30;
+ int bottom = 40;
+ layerDrawable.setLayerInsetRelative(0, start, top, end, bottom);
+ assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + start + end,
+ layerDrawable.getIntrinsicWidth());
+ start += 5;
+ layerDrawable.setLayerInsetStart(0, start);
+ assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + start + end,
+ layerDrawable.getIntrinsicWidth());
+ assertEquals(start, layerDrawable.getLayerInsetStart(0));
+
+ try {
+ layerDrawable.setLayerInset(1, start, top, end, bottom);
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testGetLayerInsetStart() {
+ Drawable[] array = new Drawable[] { new BitmapDrawable() };
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ // set inset for layer 0
+ int start = 10;
+ int top = 20;
+ int end = 30;
+ int bottom = 40;
+ layerDrawable.setLayerInsetRelative(0, start, top, end, bottom);
+ assertEquals(start, layerDrawable.getLayerInsetStart(0));
+ start += 5;
+ layerDrawable.setLayerInsetStart(0, start);
+ assertEquals(start, layerDrawable.getLayerInsetStart(0));
+
+ try {
+ layerDrawable.getLayerInsetStart(1);
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testSetLayerInsetEnd() {
+ Drawable[] array = new Drawable[] { new BitmapDrawable() };
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ // set inset for layer 0
+ int start = 10;
+ int top = 20;
+ int end = 30;
+ int bottom = 40;
+ layerDrawable.setLayerInsetRelative(0, start, top, end, bottom);
+ assertEquals(end, layerDrawable.getLayerInsetEnd(0));
+ assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + start + end,
+ layerDrawable.getIntrinsicWidth());
+ end += 5;
+ layerDrawable.setLayerInsetEnd(0, end);
+ assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + start + end,
+ layerDrawable.getIntrinsicWidth());
+ assertEquals(end, layerDrawable.getLayerInsetEnd(0));
+
+ try {
+ layerDrawable.setLayerInsetEnd(1, end);
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testGetLayerInsetEnd() {
+ Drawable[] array = new Drawable[] { new BitmapDrawable() };
+ LayerDrawable layerDrawable = new LayerDrawable(array);
+
+ // set inset for layer 0
+ int start = 10;
+ int top = 20;
+ int end = 30;
+ int bottom = 40;
+ layerDrawable.setLayerInsetRelative(0, start, top, end, bottom);
+ assertEquals(end, layerDrawable.getLayerInsetEnd(0));
+ end += 5;
+ layerDrawable.setLayerInsetEnd(0, end);
+ assertEquals(end, layerDrawable.getLayerInsetEnd(0));
+
+ try {
+ layerDrawable.getLayerInsetEnd(1);
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ }
+ }
+
+
+
private static class MockDrawable extends Drawable {
private boolean mCalledSetDither = false;
private boolean mCalledSetAlpha = false;
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
index 9851ad8..7368376 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
@@ -763,12 +763,6 @@
CamcorderProfile profile = CamcorderProfile.get(cameraId, profileId);
Size videoSz = new Size(profile.videoFrameWidth, profile.videoFrameHeight);
- if (!mSupportedVideoSizes.contains(videoSz)) {
- mCollector.addMessage("Video size " + videoSz.toString() + " for profile ID " +
- profileId + " must be one of the camera device supported video size!");
- continue;
- }
-
Size maxPreviewSize = mOrderedPreviewSizes.get(0);
if (mStaticInfo.isHardwareLevelLegacy() &&
@@ -778,6 +772,12 @@
continue;
}
+ if (!mSupportedVideoSizes.contains(videoSz)) {
+ mCollector.addMessage("Video size " + videoSz.toString() + " for profile ID " +
+ profileId + " must be one of the camera device supported video size!");
+ continue;
+ }
+
// For LEGACY, find closest supported smaller or equal JPEG size to the current video
// size; if no size is smaller than the video, pick the smallest JPEG size. The assert
// for video size above guarantees that for LIMITED or FULL, we select videoSz here.
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyGenParameterSpecTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyGenParameterSpecTest.java
new file mode 100644
index 0000000..a3e5d96
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyGenParameterSpecTest.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.test.MoreAsserts;
+
+import junit.framework.TestCase;
+
+import java.math.BigInteger;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECGenParameterSpec;
+import java.util.Arrays;
+import java.util.Date;
+
+import javax.security.auth.x500.X500Principal;
+
+public class KeyGenParameterSpecTest extends TestCase {
+
+ private static final X500Principal DEFAULT_CERT_SUBJECT = new X500Principal("CN=fake");
+ private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1");
+ private static final Date DEFAULT_CERT_NOT_BEFORE = new Date(0L); // Jan 1 1970
+ private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048
+
+ public void testDefaults() {
+ // Set only the mandatory parameters and assert values returned by getters.
+
+ KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
+ "arbitrary", KeyProperties.PURPOSE_ENCRYPT)
+ .build();
+
+ assertEquals("arbitrary", spec.getKeystoreAlias());
+ assertEquals(KeyProperties.PURPOSE_ENCRYPT, spec.getPurposes());
+ assertNull(null, spec.getAlgorithmParameterSpec());
+ MoreAsserts.assertEmpty(Arrays.asList(spec.getBlockModes()));
+ assertEquals(DEFAULT_CERT_NOT_BEFORE, spec.getCertificateNotBefore());
+ assertEquals(DEFAULT_CERT_NOT_AFTER, spec.getCertificateNotAfter());
+ assertEquals(DEFAULT_CERT_SERIAL_NUMBER, spec.getCertificateSerialNumber());
+ assertEquals(DEFAULT_CERT_SUBJECT, spec.getCertificateSubject());
+ assertFalse(spec.isDigestsSpecified());
+ try {
+ spec.getDigests();
+ fail();
+ } catch (IllegalStateException expected) {}
+ MoreAsserts.assertEmpty(Arrays.asList(spec.getEncryptionPaddings()));
+ assertEquals(-1, spec.getKeySize());
+ assertNull(spec.getKeyValidityStart());
+ assertNull(spec.getKeyValidityForOriginationEnd());
+ assertNull(spec.getKeyValidityForConsumptionEnd());
+ assertTrue(spec.isRandomizedEncryptionRequired());
+ MoreAsserts.assertEmpty(Arrays.asList(spec.getSignaturePaddings()));
+ assertFalse(spec.isUserAuthenticationRequired());
+ assertEquals(-1, spec.getUserAuthenticationValidityDurationSeconds());
+ }
+
+ public void testSettersReflectedInGetters() {
+ // Set all parameters to non-default values and then assert that getters reflect that.
+
+ Date certNotBeforeDate = new Date(System.currentTimeMillis());
+ Date certNotAfterDate = new Date(System.currentTimeMillis() + 12345678);
+ Date keyValidityStartDate = new Date(System.currentTimeMillis() - 2222222);
+ Date keyValidityEndDateForOrigination = new Date(System.currentTimeMillis() + 11111111);
+ Date keyValidityEndDateForConsumption = new Date(System.currentTimeMillis() + 33333333);
+ AlgorithmParameterSpec algSpecificParams = new ECGenParameterSpec("secp256r1");
+
+ KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
+ "arbitrary", KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_ENCRYPT)
+ .setAlgorithmParameterSpec(algSpecificParams)
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM, KeyProperties.BLOCK_MODE_CBC)
+ .setCertificateNotBefore(certNotBeforeDate)
+ .setCertificateNotAfter(certNotAfterDate)
+ .setCertificateSerialNumber(new BigInteger("13946146"))
+ .setCertificateSubject(new X500Principal("CN=test"))
+ .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA384)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP,
+ KeyProperties.ENCRYPTION_PADDING_PKCS7)
+ .setKeySize(1234)
+ .setKeyValidityStart(keyValidityStartDate)
+ .setKeyValidityForOriginationEnd(keyValidityEndDateForOrigination)
+ .setKeyValidityForConsumptionEnd(keyValidityEndDateForConsumption)
+ .setRandomizedEncryptionRequired(false)
+ .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PSS,
+ KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
+ .setUserAuthenticationRequired(true)
+ .setUserAuthenticationValidityDurationSeconds(12345)
+ .build();
+
+ assertEquals("arbitrary", spec.getKeystoreAlias());
+ assertEquals(
+ KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_ENCRYPT, spec.getPurposes());
+ assertSame(algSpecificParams, spec.getAlgorithmParameterSpec());
+ MoreAsserts.assertContentsInOrder(Arrays.asList(spec.getBlockModes()),
+ KeyProperties.BLOCK_MODE_GCM, KeyProperties.BLOCK_MODE_CBC);
+ assertEquals(certNotBeforeDate, spec.getCertificateNotBefore());
+ assertEquals(certNotAfterDate, spec.getCertificateNotAfter());
+ assertEquals(new BigInteger("13946146"), spec.getCertificateSerialNumber());
+ assertEquals(new X500Principal("CN=test"), spec.getCertificateSubject());
+ assertTrue(spec.isDigestsSpecified());
+ MoreAsserts.assertContentsInOrder(Arrays.asList(spec.getDigests()),
+ KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA384);
+ MoreAsserts.assertContentsInOrder(Arrays.asList(spec.getEncryptionPaddings()),
+ KeyProperties.ENCRYPTION_PADDING_RSA_OAEP, KeyProperties.ENCRYPTION_PADDING_PKCS7);
+ assertEquals(1234, spec.getKeySize());
+ assertEquals(keyValidityStartDate, spec.getKeyValidityStart());
+ assertEquals(keyValidityEndDateForOrigination, spec.getKeyValidityForOriginationEnd());
+ assertEquals(keyValidityEndDateForConsumption, spec.getKeyValidityForConsumptionEnd());
+ assertFalse(spec.isRandomizedEncryptionRequired());
+ MoreAsserts.assertContentsInOrder(Arrays.asList(spec.getSignaturePaddings()),
+ KeyProperties.SIGNATURE_PADDING_RSA_PSS, KeyProperties.SIGNATURE_PADDING_RSA_PKCS1);
+ assertTrue(spec.isUserAuthenticationRequired());
+ assertEquals(12345, spec.getUserAuthenticationValidityDurationSeconds());
+ }
+
+ public void testNullAliasNotPermitted() {
+ try {
+ new KeyGenParameterSpec.Builder(null, KeyProperties.PURPOSE_ENCRYPT);
+ fail();
+ } catch (NullPointerException expected) {}
+ }
+
+ public void testEmptyAliasNotPermitted() {
+ try {
+ new KeyGenParameterSpec.Builder("", KeyProperties.PURPOSE_ENCRYPT);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ public void testSetKeyValidityEndDateAppliesToBothEndDates() {
+ Date date = new Date(System.currentTimeMillis() + 555555);
+ KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
+ "ignore", KeyProperties.PURPOSE_VERIFY)
+ .setKeyValidityEnd(date)
+ .build();
+ assertEquals(date, spec.getKeyValidityForOriginationEnd());
+ assertEquals(date, spec.getKeyValidityForConsumptionEnd());
+ }
+
+ public void testSetUserAuthenticationValidityDurationSecondsValidityCheck() {
+ KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder("alias", 0);
+ try {
+ builder.setUserAuthenticationValidityDurationSeconds(-2);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+
+ try {
+ builder.setUserAuthenticationValidityDurationSeconds(-100);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+
+ try {
+ builder.setUserAuthenticationValidityDurationSeconds(Integer.MIN_VALUE);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+
+ builder.setUserAuthenticationValidityDurationSeconds(-1);
+ builder.setUserAuthenticationValidityDurationSeconds(0);
+ builder.setUserAuthenticationValidityDurationSeconds(1);
+ builder.setUserAuthenticationValidityDurationSeconds(Integer.MAX_VALUE);
+
+ try {
+ builder.setUserAuthenticationValidityDurationSeconds(-2);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ public void testImmutabilityViaSetterParams() {
+ // Assert that all mutable parameters provided to setters are copied to ensure that values
+ // returned by getters never change.
+ String[] blockModes =
+ new String[] {KeyProperties.BLOCK_MODE_GCM, KeyProperties.BLOCK_MODE_CBC};
+ String[] originalBlockModes = blockModes.clone();
+ Date certNotBeforeDate = new Date(System.currentTimeMillis());
+ Date originalCertNotBeforeDate = new Date(certNotBeforeDate.getTime());
+ Date certNotAfterDate = new Date(System.currentTimeMillis() + 12345678);
+ Date originalCertNotAfterDate = new Date(certNotAfterDate.getTime());
+ Date keyValidityStartDate = new Date(System.currentTimeMillis() - 2222222);
+ Date originalKeyValidityStartDate = new Date(keyValidityStartDate.getTime());
+ Date keyValidityEndDateForOrigination = new Date(System.currentTimeMillis() + 11111111);
+ Date originalKeyValidityEndDateForOrigination =
+ new Date(keyValidityEndDateForOrigination.getTime());
+ Date keyValidityEndDateForConsumption = new Date(System.currentTimeMillis() + 33333333);
+ Date originalKeyValidityEndDateForConsumption =
+ new Date(keyValidityEndDateForConsumption.getTime());
+ String[] digests = new String[] {KeyProperties.DIGEST_MD5, KeyProperties.DIGEST_SHA512};
+ String[] originalDigests = digests.clone();
+ String[] encryptionPaddings = new String[] {
+ KeyProperties.ENCRYPTION_PADDING_RSA_OAEP, KeyProperties.ENCRYPTION_PADDING_PKCS7};
+ String[] originalEncryptionPaddings = encryptionPaddings.clone();
+ String[] signaturePaddings = new String[] {
+ KeyProperties.SIGNATURE_PADDING_RSA_PSS, KeyProperties.SIGNATURE_PADDING_RSA_PKCS1};
+ String[] originalSignaturePaddings = signaturePaddings.clone();
+
+ KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
+ "arbitrary", KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_ENCRYPT)
+ .setBlockModes(blockModes)
+ .setCertificateNotBefore(certNotBeforeDate)
+ .setCertificateNotAfter(certNotAfterDate)
+ .setDigests(digests)
+ .setEncryptionPaddings(encryptionPaddings)
+ .setKeyValidityStart(keyValidityStartDate)
+ .setKeyValidityForOriginationEnd(keyValidityEndDateForOrigination)
+ .setKeyValidityForConsumptionEnd(keyValidityEndDateForConsumption)
+ .setSignaturePaddings(signaturePaddings)
+ .build();
+
+ assertEquals(Arrays.asList(originalBlockModes), Arrays.asList(spec.getBlockModes()));
+ blockModes[0] = null;
+ assertEquals(Arrays.asList(originalBlockModes), Arrays.asList(spec.getBlockModes()));
+
+ assertEquals(originalCertNotBeforeDate, spec.getCertificateNotBefore());
+ certNotBeforeDate.setTime(1234567890L);
+ assertEquals(originalCertNotBeforeDate, spec.getCertificateNotBefore());
+
+ assertEquals(originalCertNotAfterDate, spec.getCertificateNotAfter());
+ certNotAfterDate.setTime(1234567890L);
+ assertEquals(originalCertNotAfterDate, spec.getCertificateNotAfter());
+
+ assertEquals(Arrays.asList(originalDigests), Arrays.asList(spec.getDigests()));
+ digests[1] = null;
+ assertEquals(Arrays.asList(originalDigests), Arrays.asList(spec.getDigests()));
+
+ assertEquals(Arrays.asList(originalEncryptionPaddings),
+ Arrays.asList(spec.getEncryptionPaddings()));
+ encryptionPaddings[0] = null;
+ assertEquals(Arrays.asList(originalEncryptionPaddings),
+ Arrays.asList(spec.getEncryptionPaddings()));
+
+ assertEquals(originalKeyValidityStartDate, spec.getKeyValidityStart());
+ keyValidityStartDate.setTime(1234567890L);
+ assertEquals(originalKeyValidityStartDate, spec.getKeyValidityStart());
+
+ assertEquals(originalKeyValidityEndDateForOrigination,
+ spec.getKeyValidityForOriginationEnd());
+ keyValidityEndDateForOrigination.setTime(1234567890L);
+ assertEquals(originalKeyValidityEndDateForOrigination,
+ spec.getKeyValidityForOriginationEnd());
+
+ assertEquals(originalKeyValidityEndDateForConsumption,
+ spec.getKeyValidityForConsumptionEnd());
+ keyValidityEndDateForConsumption.setTime(1234567890L);
+ assertEquals(originalKeyValidityEndDateForConsumption,
+ spec.getKeyValidityForConsumptionEnd());
+
+ assertEquals(Arrays.asList(originalSignaturePaddings),
+ Arrays.asList(spec.getSignaturePaddings()));
+ signaturePaddings[1] = null;
+ assertEquals(Arrays.asList(originalSignaturePaddings),
+ Arrays.asList(spec.getSignaturePaddings()));
+ }
+
+ public void testImmutabilityViaGetterReturnValues() {
+ // Assert that none of the mutable return values from getters modify the state of the spec.
+
+ KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
+ "arbitrary", KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_ENCRYPT)
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM, KeyProperties.BLOCK_MODE_CBC)
+ .setCertificateNotBefore(new Date(System.currentTimeMillis()))
+ .setCertificateNotAfter(new Date(System.currentTimeMillis() + 12345678))
+ .setDigests(KeyProperties.DIGEST_MD5, KeyProperties.DIGEST_SHA512)
+ .setEncryptionPaddings(
+ KeyProperties.ENCRYPTION_PADDING_RSA_OAEP,
+ KeyProperties.ENCRYPTION_PADDING_PKCS7)
+ .setKeyValidityStart(new Date(System.currentTimeMillis() - 2222222))
+ .setKeyValidityForOriginationEnd(new Date(System.currentTimeMillis() + 11111111))
+ .setKeyValidityForConsumptionEnd(new Date(System.currentTimeMillis() + 33333333))
+ .setSignaturePaddings(
+ KeyProperties.SIGNATURE_PADDING_RSA_PSS,
+ KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
+ .build();
+
+ String[] originalBlockModes = spec.getBlockModes().clone();
+ spec.getBlockModes()[0] = null;
+ assertEquals(Arrays.asList(originalBlockModes), Arrays.asList(spec.getBlockModes()));
+
+ Date originalCertNotBeforeDate = (Date) spec.getCertificateNotBefore().clone();
+ spec.getCertificateNotBefore().setTime(1234567890L);
+ assertEquals(originalCertNotBeforeDate, spec.getCertificateNotBefore());
+
+ Date originalCertNotAfterDate = (Date) spec.getCertificateNotAfter().clone();
+ spec.getCertificateNotAfter().setTime(1234567890L);
+ assertEquals(originalCertNotAfterDate, spec.getCertificateNotAfter());
+
+ String[] originalDigests = spec.getDigests().clone();
+ spec.getDigests()[0] = null;
+ assertEquals(Arrays.asList(originalDigests), Arrays.asList(spec.getDigests()));
+
+ String[] originalEncryptionPaddings = spec.getEncryptionPaddings().clone();
+ spec.getEncryptionPaddings()[0] = null;
+ assertEquals(Arrays.asList(originalEncryptionPaddings),
+ Arrays.asList(spec.getEncryptionPaddings()));
+
+ Date originalKeyValidityStartDate = (Date) spec.getKeyValidityStart().clone();
+ spec.getKeyValidityStart().setTime(1234567890L);
+ assertEquals(originalKeyValidityStartDate, spec.getKeyValidityStart());
+
+ Date originalKeyValidityEndDateForOrigination =
+ (Date) spec.getKeyValidityForOriginationEnd().clone();
+ spec.getKeyValidityForOriginationEnd().setTime(1234567890L);
+ assertEquals(originalKeyValidityEndDateForOrigination,
+ spec.getKeyValidityForOriginationEnd());
+
+ Date originalKeyValidityEndDateForConsumption =
+ (Date) spec.getKeyValidityForConsumptionEnd().clone();
+ spec.getKeyValidityForConsumptionEnd().setTime(1234567890L);
+ assertEquals(originalKeyValidityEndDateForConsumption,
+ spec.getKeyValidityForConsumptionEnd());
+
+ String[] originalSignaturePaddings = spec.getSignaturePaddings().clone();
+ spec.getSignaturePaddings()[0] = null;
+ assertEquals(Arrays.asList(originalSignaturePaddings),
+ Arrays.asList(spec.getSignaturePaddings()));
+ }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyInfoTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyInfoTest.java
new file mode 100644
index 0000000..2b1d6fc
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyInfoTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyInfo;
+import android.security.keystore.KeyProperties;
+
+import junit.framework.TestCase;
+
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.util.Arrays;
+import java.util.Date;
+
+public class KeyInfoTest extends TestCase {
+
+ public void testImmutabilityViaGetterReturnValues() throws Exception {
+ // Assert that none of the mutable return values from getters modify the state of the
+ // instance.
+
+ Date keyValidityStartDate = new Date(System.currentTimeMillis() - 2222222);
+ Date keyValidityEndDateForOrigination = new Date(System.currentTimeMillis() + 11111111);
+ Date keyValidityEndDateForConsumption = new Date(System.currentTimeMillis() + 33333333);
+
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
+ keyPairGenerator.initialize(new KeyGenParameterSpec.Builder(
+ KeyInfoTest.class.getSimpleName(),
+ KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_ENCRYPT)
+ .setKeySize(1024) // use smaller key size to speed the test up
+ .setKeyValidityStart(keyValidityStartDate)
+ .setKeyValidityForOriginationEnd(keyValidityEndDateForOrigination)
+ .setKeyValidityForConsumptionEnd(keyValidityEndDateForConsumption)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
+ KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
+ .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1,
+ KeyProperties.SIGNATURE_PADDING_RSA_PSS)
+ .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
+ .setBlockModes(KeyProperties.BLOCK_MODE_ECB)
+ .build());
+ KeyPair keyPair = keyPairGenerator.generateKeyPair();
+
+ PrivateKey key = keyPair.getPrivate();
+ KeyFactory keyFactory = KeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore");
+ KeyInfo info = keyFactory.getKeySpec(key, KeyInfo.class);
+
+ Date originalKeyValidityStartDate = (Date) info.getKeyValidityStart().clone();
+ info.getKeyValidityStart().setTime(1234567890L);
+ assertEquals(originalKeyValidityStartDate, info.getKeyValidityStart());
+
+ Date originalKeyValidityEndDateForOrigination =
+ (Date) info.getKeyValidityForOriginationEnd().clone();
+ info.getKeyValidityForOriginationEnd().setTime(1234567890L);
+ assertEquals(originalKeyValidityEndDateForOrigination,
+ info.getKeyValidityForOriginationEnd());
+
+ Date originalKeyValidityEndDateForConsumption =
+ (Date) info.getKeyValidityForConsumptionEnd().clone();
+ info.getKeyValidityForConsumptionEnd().setTime(1234567890L);
+ assertEquals(originalKeyValidityEndDateForConsumption,
+ info.getKeyValidityForConsumptionEnd());
+
+ String[] originalEncryptionPaddings = info.getEncryptionPaddings().clone();
+ info.getEncryptionPaddings()[0] = null;
+ assertEquals(Arrays.asList(originalEncryptionPaddings),
+ Arrays.asList(info.getEncryptionPaddings()));
+
+ String[] originalSignaturePaddings = info.getSignaturePaddings().clone();
+ info.getSignaturePaddings()[0] = null;
+ assertEquals(Arrays.asList(originalSignaturePaddings),
+ Arrays.asList(info.getSignaturePaddings()));
+
+ String[] originalDigests = info.getDigests().clone();
+ info.getDigests()[0] = null;
+ assertEquals(Arrays.asList(originalDigests), Arrays.asList(info.getDigests()));
+
+ String[] originalBlockModes = info.getBlockModes().clone();
+ info.getBlockModes()[0] = null;
+ assertEquals(Arrays.asList(originalBlockModes), Arrays.asList(info.getBlockModes()));
+ }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyProtectionTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyProtectionTest.java
new file mode 100644
index 0000000..ee24eed
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyProtectionTest.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+import android.security.keystore.KeyProperties;
+import android.security.keystore.KeyProtection;
+import android.test.MoreAsserts;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.Date;
+
+public class KeyProtectionTest extends TestCase {
+ public void testDefaults() {
+ // Set only the mandatory parameters and assert values returned by getters.
+
+ KeyProtection spec = new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
+ .build();
+
+ assertEquals(KeyProperties.PURPOSE_ENCRYPT, spec.getPurposes());
+ MoreAsserts.assertEmpty(Arrays.asList(spec.getBlockModes()));
+ assertFalse(spec.isDigestsSpecified());
+ try {
+ spec.getDigests();
+ fail();
+ } catch (IllegalStateException expected) {}
+ MoreAsserts.assertEmpty(Arrays.asList(spec.getEncryptionPaddings()));
+ assertNull(spec.getKeyValidityStart());
+ assertNull(spec.getKeyValidityForOriginationEnd());
+ assertNull(spec.getKeyValidityForConsumptionEnd());
+ assertTrue(spec.isRandomizedEncryptionRequired());
+ MoreAsserts.assertEmpty(Arrays.asList(spec.getSignaturePaddings()));
+ assertFalse(spec.isUserAuthenticationRequired());
+ assertEquals(-1, spec.getUserAuthenticationValidityDurationSeconds());
+ }
+
+ public void testSettersReflectedInGetters() {
+ // Set all parameters to non-default values and then assert that getters reflect that.
+
+ Date keyValidityStartDate = new Date(System.currentTimeMillis() - 2222222);
+ Date keyValidityEndDateForOrigination = new Date(System.currentTimeMillis() + 11111111);
+ Date keyValidityEndDateForConsumption = new Date(System.currentTimeMillis() + 33333333);
+
+ KeyProtection spec = new KeyProtection.Builder(
+ KeyProperties.PURPOSE_DECRYPT | KeyProperties.PURPOSE_VERIFY)
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM, KeyProperties.BLOCK_MODE_CTR)
+ .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
+ KeyProperties.ENCRYPTION_PADDING_PKCS7)
+ .setKeyValidityStart(keyValidityStartDate)
+ .setKeyValidityForOriginationEnd(keyValidityEndDateForOrigination)
+ .setKeyValidityForConsumptionEnd(keyValidityEndDateForConsumption)
+ .setRandomizedEncryptionRequired(false)
+ .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1,
+ KeyProperties.SIGNATURE_PADDING_RSA_PSS)
+ .setUserAuthenticationRequired(true)
+ .setUserAuthenticationValidityDurationSeconds(123456)
+ .build();
+
+ assertEquals(
+ KeyProperties.PURPOSE_DECRYPT| KeyProperties.PURPOSE_VERIFY, spec.getPurposes());
+ MoreAsserts.assertContentsInOrder(Arrays.asList(spec.getBlockModes()),
+ KeyProperties.BLOCK_MODE_GCM, KeyProperties.BLOCK_MODE_CTR);
+ assertTrue(spec.isDigestsSpecified());
+ MoreAsserts.assertContentsInOrder(Arrays.asList(spec.getDigests()),
+ KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512);
+ MoreAsserts.assertContentsInOrder(Arrays.asList(spec.getEncryptionPaddings()),
+ KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1, KeyProperties.ENCRYPTION_PADDING_PKCS7);
+ assertEquals(keyValidityStartDate, spec.getKeyValidityStart());
+ assertEquals(keyValidityEndDateForOrigination, spec.getKeyValidityForOriginationEnd());
+ assertEquals(keyValidityEndDateForConsumption, spec.getKeyValidityForConsumptionEnd());
+ assertFalse(spec.isRandomizedEncryptionRequired());
+ MoreAsserts.assertContentsInOrder(Arrays.asList(spec.getSignaturePaddings()),
+ KeyProperties.SIGNATURE_PADDING_RSA_PKCS1, KeyProperties.SIGNATURE_PADDING_RSA_PSS);
+ assertTrue(spec.isUserAuthenticationRequired());
+ assertEquals(123456, spec.getUserAuthenticationValidityDurationSeconds());
+ }
+
+ public void testSetKeyValidityEndDateAppliesToBothEndDates() {
+ Date date = new Date(System.currentTimeMillis() + 555555);
+ KeyProtection spec = new KeyProtection.Builder(
+ KeyProperties.PURPOSE_SIGN)
+ .setKeyValidityEnd(date)
+ .build();
+ assertEquals(date, spec.getKeyValidityForOriginationEnd());
+ assertEquals(date, spec.getKeyValidityForConsumptionEnd());
+ }
+
+ public void testSetUserAuthenticationValidityDurationSecondsValidityCheck() {
+ KeyProtection.Builder builder = new KeyProtection.Builder(0);
+ try {
+ builder.setUserAuthenticationValidityDurationSeconds(-2);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+
+ try {
+ builder.setUserAuthenticationValidityDurationSeconds(-100);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+
+ try {
+ builder.setUserAuthenticationValidityDurationSeconds(Integer.MIN_VALUE);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+
+ builder.setUserAuthenticationValidityDurationSeconds(-1);
+ builder.setUserAuthenticationValidityDurationSeconds(0);
+ builder.setUserAuthenticationValidityDurationSeconds(1);
+ builder.setUserAuthenticationValidityDurationSeconds(Integer.MAX_VALUE);
+
+ try {
+ builder.setUserAuthenticationValidityDurationSeconds(-2);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ public void testImmutabilityViaSetterParams() {
+ // Assert that all mutable parameters provided to setters are copied to ensure that values
+ // returned by getters never change.
+ String[] blockModes =
+ new String[] {KeyProperties.BLOCK_MODE_GCM, KeyProperties.BLOCK_MODE_CBC};
+ String[] originalBlockModes = blockModes.clone();
+ Date keyValidityStartDate = new Date(System.currentTimeMillis() - 2222222);
+ Date originalKeyValidityStartDate = new Date(keyValidityStartDate.getTime());
+ Date keyValidityEndDateForOrigination = new Date(System.currentTimeMillis() + 11111111);
+ Date originalKeyValidityEndDateForOrigination =
+ new Date(keyValidityEndDateForOrigination.getTime());
+ Date keyValidityEndDateForConsumption = new Date(System.currentTimeMillis() + 33333333);
+ Date originalKeyValidityEndDateForConsumption =
+ new Date(keyValidityEndDateForConsumption.getTime());
+ String[] digests = new String[] {KeyProperties.DIGEST_MD5, KeyProperties.DIGEST_SHA512};
+ String[] originalDigests = digests.clone();
+ String[] encryptionPaddings = new String[] {
+ KeyProperties.ENCRYPTION_PADDING_RSA_OAEP, KeyProperties.ENCRYPTION_PADDING_PKCS7};
+ String[] originalEncryptionPaddings = encryptionPaddings.clone();
+ String[] signaturePaddings = new String[] {
+ KeyProperties.SIGNATURE_PADDING_RSA_PSS, KeyProperties.SIGNATURE_PADDING_RSA_PKCS1};
+ String[] originalSignaturePaddings = signaturePaddings.clone();
+
+ KeyProtection spec = new KeyProtection.Builder(
+ KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_ENCRYPT)
+ .setBlockModes(blockModes)
+ .setDigests(digests)
+ .setEncryptionPaddings(encryptionPaddings)
+ .setKeyValidityStart(keyValidityStartDate)
+ .setKeyValidityForOriginationEnd(keyValidityEndDateForOrigination)
+ .setKeyValidityForConsumptionEnd(keyValidityEndDateForConsumption)
+ .setSignaturePaddings(signaturePaddings)
+ .build();
+
+ assertEquals(Arrays.asList(originalBlockModes), Arrays.asList(spec.getBlockModes()));
+ blockModes[0] = null;
+ assertEquals(Arrays.asList(originalBlockModes), Arrays.asList(spec.getBlockModes()));
+
+ assertEquals(Arrays.asList(originalDigests), Arrays.asList(spec.getDigests()));
+ digests[1] = null;
+ assertEquals(Arrays.asList(originalDigests), Arrays.asList(spec.getDigests()));
+
+ assertEquals(Arrays.asList(originalEncryptionPaddings),
+ Arrays.asList(spec.getEncryptionPaddings()));
+ encryptionPaddings[0] = null;
+ assertEquals(Arrays.asList(originalEncryptionPaddings),
+ Arrays.asList(spec.getEncryptionPaddings()));
+
+ assertEquals(originalKeyValidityStartDate, spec.getKeyValidityStart());
+ keyValidityStartDate.setTime(1234567890L);
+ assertEquals(originalKeyValidityStartDate, spec.getKeyValidityStart());
+
+ assertEquals(originalKeyValidityEndDateForOrigination,
+ spec.getKeyValidityForOriginationEnd());
+ keyValidityEndDateForOrigination.setTime(1234567890L);
+ assertEquals(originalKeyValidityEndDateForOrigination,
+ spec.getKeyValidityForOriginationEnd());
+
+ assertEquals(originalKeyValidityEndDateForConsumption,
+ spec.getKeyValidityForConsumptionEnd());
+ keyValidityEndDateForConsumption.setTime(1234567890L);
+ assertEquals(originalKeyValidityEndDateForConsumption,
+ spec.getKeyValidityForConsumptionEnd());
+
+ assertEquals(Arrays.asList(originalSignaturePaddings),
+ Arrays.asList(spec.getSignaturePaddings()));
+ signaturePaddings[1] = null;
+ assertEquals(Arrays.asList(originalSignaturePaddings),
+ Arrays.asList(spec.getSignaturePaddings()));
+ }
+
+ public void testImmutabilityViaGetterReturnValues() {
+ // Assert that none of the mutable return values from getters modify the state of the spec.
+
+ KeyProtection spec = new KeyProtection.Builder(
+ KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_ENCRYPT)
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM, KeyProperties.BLOCK_MODE_CBC)
+ .setDigests(KeyProperties.DIGEST_MD5, KeyProperties.DIGEST_SHA512)
+ .setEncryptionPaddings(
+ KeyProperties.ENCRYPTION_PADDING_RSA_OAEP,
+ KeyProperties.ENCRYPTION_PADDING_PKCS7)
+ .setKeyValidityStart(new Date(System.currentTimeMillis() - 2222222))
+ .setKeyValidityForOriginationEnd(new Date(System.currentTimeMillis() + 11111111))
+ .setKeyValidityForConsumptionEnd(new Date(System.currentTimeMillis() + 33333333))
+ .setSignaturePaddings(
+ KeyProperties.SIGNATURE_PADDING_RSA_PSS,
+ KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
+ .build();
+
+ String[] originalBlockModes = spec.getBlockModes().clone();
+ spec.getBlockModes()[0] = null;
+ assertEquals(Arrays.asList(originalBlockModes), Arrays.asList(spec.getBlockModes()));
+
+ String[] originalDigests = spec.getDigests().clone();
+ spec.getDigests()[0] = null;
+ assertEquals(Arrays.asList(originalDigests), Arrays.asList(spec.getDigests()));
+
+ String[] originalEncryptionPaddings = spec.getEncryptionPaddings().clone();
+ spec.getEncryptionPaddings()[0] = null;
+ assertEquals(Arrays.asList(originalEncryptionPaddings),
+ Arrays.asList(spec.getEncryptionPaddings()));
+
+ Date originalKeyValidityStartDate = (Date) spec.getKeyValidityStart().clone();
+ spec.getKeyValidityStart().setTime(1234567890L);
+ assertEquals(originalKeyValidityStartDate, spec.getKeyValidityStart());
+
+ Date originalKeyValidityEndDateForOrigination =
+ (Date) spec.getKeyValidityForOriginationEnd().clone();
+ spec.getKeyValidityForOriginationEnd().setTime(1234567890L);
+ assertEquals(originalKeyValidityEndDateForOrigination,
+ spec.getKeyValidityForOriginationEnd());
+
+ Date originalKeyValidityEndDateForConsumption =
+ (Date) spec.getKeyValidityForConsumptionEnd().clone();
+ spec.getKeyValidityForConsumptionEnd().setTime(1234567890L);
+ assertEquals(originalKeyValidityEndDateForConsumption,
+ spec.getKeyValidityForConsumptionEnd());
+
+ String[] originalSignaturePaddings = spec.getSignaturePaddings().clone();
+ spec.getSignaturePaddings()[0] = null;
+ assertEquals(Arrays.asList(originalSignaturePaddings),
+ Arrays.asList(spec.getSignaturePaddings()));
+ }
+}
diff --git a/tests/tests/security/jni/Android.mk b/tests/tests/security/jni/Android.mk
index 7106385..6bef886 100644
--- a/tests/tests/security/jni/Android.mk
+++ b/tests/tests/security/jni/Android.mk
@@ -28,7 +28,6 @@
android_security_cts_LinuxRngTest.cpp \
android_security_cts_LoadEffectLibraryTest.cpp \
android_security_cts_NativeCodeTest.cpp \
- android_security_cts_SeccompDeathTestService.cpp \
android_security_cts_SELinuxTest.cpp \
android_security_cts_MMapExecutableTest.cpp \
android_security_cts_AudioPolicyBinderTest.cpp
diff --git a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
index 424dbaf..1051a82 100644
--- a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
+++ b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
@@ -22,7 +22,6 @@
extern int register_android_security_cts_LinuxRngTest(JNIEnv*);
extern int register_android_security_cts_NativeCodeTest(JNIEnv*);
extern int register_android_security_cts_LoadEffectLibraryTest(JNIEnv*);
-extern int register_android_security_cts_SeccompDeathTestService(JNIEnv*);
extern int register_android_security_cts_SELinuxTest(JNIEnv*);
extern int register_android_security_cts_MMapExecutableTest(JNIEnv* env);
extern int register_android_security_cts_AudioPolicyBinderTest(JNIEnv* env);
@@ -50,10 +49,6 @@
return JNI_ERR;
}
- if (register_android_security_cts_SeccompDeathTestService(env)) {
- return JNI_ERR;
- }
-
if (register_android_security_cts_SELinuxTest(env)) {
return JNI_ERR;
}
diff --git a/tests/tests/security/jni/android_security_cts_NativeCodeTest.cpp b/tests/tests/security/jni/android_security_cts_NativeCodeTest.cpp
index 00765c6..350309b 100644
--- a/tests/tests/security/jni/android_security_cts_NativeCodeTest.cpp
+++ b/tests/tests/security/jni/android_security_cts_NativeCodeTest.cpp
@@ -34,6 +34,7 @@
#include <errno.h>
#include <inttypes.h>
#include <linux/sysctl.h>
+#include <arpa/inet.h>
/*
* Returns true iff this device is vulnerable to CVE-2013-2094.
@@ -227,6 +228,28 @@
return !vulnerable;
}
+static jboolean android_security_cts_NativeCodeTest_doPingPongRootTest(JNIEnv*, jobject)
+{
+ int icmp_sock;
+ struct sockaddr sock_addr;
+
+ memset(&sock_addr, 0, sizeof(sock_addr));
+ icmp_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
+ sock_addr.sa_family = AF_INET;
+
+ /* first connect */
+ connect(icmp_sock, &sock_addr, sizeof(sock_addr));
+
+ /* disconnect */
+ sock_addr.sa_family = AF_UNSPEC;
+ connect(icmp_sock, &sock_addr, sizeof(sock_addr));
+
+ /* second disconnect -> crash */
+ sock_addr.sa_family = AF_UNSPEC;
+ connect(icmp_sock, &sock_addr, sizeof(sock_addr));
+
+ return true;
+}
static JNINativeMethod gMethods[] = {
{ "doPerfEventTest", "()Z",
@@ -241,6 +264,8 @@
(void *) android_security_cts_NativeCodeTest_doFutexTest },
{ "doNvmapIocFromIdTest", "()Z",
(void *) android_security_cts_NativeCodeTest_doNvmapIocFromIdTest },
+ { "doPingPongRootTest", "()Z",
+ (void *) android_security_cts_NativeCodeTest_doPingPongRootTest },
};
int register_android_security_cts_NativeCodeTest(JNIEnv* env)
@@ -249,3 +274,4 @@
return env->RegisterNatives(clazz, gMethods,
sizeof(gMethods) / sizeof(JNINativeMethod));
}
+
diff --git a/tests/tests/security/jni/android_security_cts_SeccompDeathTestService.cpp b/tests/tests/security/jni/android_security_cts_SeccompDeathTestService.cpp
deleted file mode 100644
index eb32521..0000000
--- a/tests/tests/security/jni/android_security_cts_SeccompDeathTestService.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <jni.h>
-#include <signal.h>
-#include <unistd.h>
-
-void android_security_cts_SeccompDeathTestService_testSigSysSelf(JNIEnv* env, jobject thiz)
-{
- kill(getpid(), SIGSYS);
-}
-
-static JNINativeMethod methods[] = {
- { "testSigSysSelf", "()V",
- (void *)android_security_cts_SeccompDeathTestService_testSigSysSelf }
-};
-
-int register_android_security_cts_SeccompDeathTestService(JNIEnv* env) {
- jclass clazz = env->FindClass("android/security/cts/SeccompDeathTestService");
- return env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(JNINativeMethod));
-}
diff --git a/tests/tests/security/src/android/security/cts/NativeCodeTest.java b/tests/tests/security/src/android/security/cts/NativeCodeTest.java
index a2f8c09..ab41b4f 100644
--- a/tests/tests/security/src/android/security/cts/NativeCodeTest.java
+++ b/tests/tests/security/src/android/security/cts/NativeCodeTest.java
@@ -58,6 +58,12 @@
doNvmapIocFromIdTest());
}
+ public void testPingPongRoot() throws Exception {
+ assertTrue("Device is vulnerable to CVE-2015-3636, a vulnerability in the ping "
+ + "socket implementation. Please apply the security patch at "
+ + "https://github.com/torvalds/linux/commit/a134f083e79f",
+ doPingPongRootTest());
+ }
/**
* Returns true iff this device is vulnerable to CVE-2013-2094.
* A patch for CVE-2013-2094 can be found at
@@ -120,4 +126,18 @@
* false if the device is vulnerable.
*/
private static native boolean doCVE20141710Test();
+
+ /**
+ * CVE-2015-3636
+ *
+ * Returns true if the patch is applied, crashes the system otherwise.
+ *
+ * Detects if the following patch is present.
+ * https://github.com/torvalds/linux/commit/a134f083e79f
+ *
+ * Credit: Wen Xu and wushi of KeenTeam.
+ * http://seclists.org/oss-sec/2015/q2/333
+ */
+ private static native boolean doPingPongRootTest();
+
}
diff --git a/tests/tests/security/src/android/security/cts/SeccompBpfTest.java b/tests/tests/security/src/android/security/cts/SeccompBpfTest.java
deleted file mode 100644
index b7d8f2e..0000000
--- a/tests/tests/security/src/android/security/cts/SeccompBpfTest.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-import android.test.AndroidTestCase;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.util.Log;
-
-/**
- * Test for seccomp-bpf sandboxing technology. This makes use of the
- * SeccompDeathTestService to run sandboxing death tests out-of-process.
- */
-public class SeccompBpfTest extends AndroidTestCase implements ServiceConnection,
- IBinder.DeathRecipient {
- static final String TAG = "SeccompBpfTest";
-
- /**
- * Message sent from the SeccompDeathTestService before it runs a test.
- */
- static final int MSG_TEST_STARTED = 1;
- /**
- * Message sent from the SeccompDeathTestService after a test exits cleanly.
- */
- static final int MSG_TEST_ENDED_CLEAN = 2;
-
- /**
- * Dedicated thread used to receive messages from the SeccompDeathTestService.
- */
- final private HandlerThread mHandlerThread = new HandlerThread("SeccompBpfTest handler");
- /**
- * Messenger that runs on mHandlerThread.
- */
- private Messenger mMessenger;
-
- /**
- * Condition that blocks the test/instrumentation thread that runs the
- * test cases, while the SeccompDeathTestService runs the test out-of-process.
- */
- final private ConditionVariable mCondition = new ConditionVariable();
-
- /**
- * The SeccompDeathTestService number to run.
- */
- private int mTestNumber = -1;
-
- /**
- * If the test has started.
- */
- private boolean mTestStarted = false;
- /**
- * If the test ended (either cleanly or with death).
- */
- private boolean mTestEnded = false;
- /**
- * If the test ended cleanly or died.
- */
- private boolean mTestDied = false;
-
- public void testDeathTest() {
- runDeathTest(SeccompDeathTestService.TEST_DEATH_TEST);
- assertTrue(mTestDied);
- }
-
- public void testCleanTest() {
- runDeathTest(SeccompDeathTestService.TEST_CLEAN_TEST);
- assertFalse(mTestDied);
- }
-
- public void testSigSysSelf() {
- runDeathTest(SeccompDeathTestService.TEST_SIGSYS_SELF);
- assertTrue(mTestDied);
- }
-
- /**
- * Runs a death test by its test number, which needs to match a value in
- * SeccompDeathTestService.
- *
- * This blocks until the completion of the test, after which the test body
- * can use mTestEnded/mTestDied to see if the test died.
- */
- public void runDeathTest(final int testNumber) {
- mTestStarted = false;
- mTestEnded = false;
- mTestDied = false;
-
- mTestNumber = testNumber;
-
- Log.d(TAG, "Starting runDeathTest");
- launchDeathTestService();
- mCondition.block();
-
- assertTrue(mTestStarted);
- assertTrue(mTestEnded);
- }
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
- mHandlerThread.start();
- mMessenger = new Messenger(new Handler(mHandlerThread.getLooper()) {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_TEST_STARTED:
- onTestStarted();
- break;
- case MSG_TEST_ENDED_CLEAN:
- onTestEnded(false);
- break;
- default:
- super.handleMessage(msg);
- }
- }
- });
- }
-
- @Override
- public void tearDown() throws Exception {
- try {
- mHandlerThread.quitSafely();
- } finally {
- super.tearDown();
- }
- }
-
- private void launchDeathTestService() {
- Log.d(TAG, "launchDeathTestService");
- mCondition.close();
-
- Intent intent = new Intent();
- intent.setComponent(new ComponentName("com.android.cts.security", "android.security.cts.SeccompDeathTestService"));
-
- if (!getContext().bindService(intent, this, Context.BIND_AUTO_CREATE)) {
- mCondition.open();
- fail("Failed to start DeathTestService");
- }
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- Log.d(TAG, "onServiceConnected");
-
- Messenger remoteMessenger = new Messenger(service);
- Message msg = Message.obtain(null, SeccompDeathTestService.MSG_RUN_TEST);
- msg.getData().putBinder(SeccompDeathTestService.REPLY_BINDER_NAME, mMessenger.getBinder());
- msg.getData().putInt(SeccompDeathTestService.RUN_TEST_IDENTIFIER, mTestNumber);
-
- try {
- service.linkToDeath(this, 0);
- remoteMessenger.send(msg);
- } catch (RemoteException e) {
- Log.e(TAG, "Error setting up SeccompDeathTestService: " + e.getMessage());
- }
- Log.d(TAG, "Send MSG_TEST_START");
- }
-
- private void onTestStarted() {
- Log.d(TAG, "onTestStarted");
- mTestStarted = true;
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- Log.d(TAG, "onServiceDisconnected");
- }
-
- @Override
- public void binderDied() {
- Log.d(TAG, "binderDied");
- if (mTestEnded)
- return;
- onTestEnded(true);
- }
-
- private void onTestEnded(boolean died) {
- Log.d(TAG, "onTestEnded, died=" + died);
- mTestEnded = true;
- mTestDied = died;
- getContext().unbindService(this);
- mCondition.open();
- }
-}
diff --git a/tests/tests/security/src/android/security/cts/SeccompDeathTestService.java b/tests/tests/security/src/android/security/cts/SeccompDeathTestService.java
deleted file mode 100644
index c78ea35..0000000
--- a/tests/tests/security/src/android/security/cts/SeccompDeathTestService.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.util.Log;
-
-/**
- * Service used to run tests for seccomp-bpf sandboxing. Since sandbox violations
- * result in process termination, they cannot be run from within the test case
- * itself. The SeccompBpfTest starts this service to run code out-of-process and
- * then observes when the Binder channel dies. If the test does not die, the
- * service reports back to the test that it exited cleanly.
- */
-public class SeccompDeathTestService extends Service {
- static final String TAG = SeccompBpfTest.TAG;
-
- static {
- System.loadLibrary("ctssecurity_jni");
- }
-
- /**
- * Message sent from SeccompBpfTest to run a test.
- */
- final static int MSG_RUN_TEST = 100;
- /**
- * In MSG_RUN_TEST, the test number to run.
- */
- final static String RUN_TEST_IDENTIFIER = "android.security.cts.SeccompDeathTestService.testID";
- /**
- * In MSG_RUN_TEST, the Binder on which to report clean death.
- */
- static final String REPLY_BINDER_NAME = "android.security.cts.SeccompBpfTest";
-
- // Test numbers that map to test methods in this service.
- final static int TEST_DEATH_TEST = 1;
- final static int TEST_CLEAN_TEST = 2;
- final static int TEST_SIGSYS_SELF = 3;
-
- final private Messenger mMessenger = new Messenger(new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_RUN_TEST:
- runTest(msg);
- break;
- default:
- super.handleMessage(msg);
- }
- }
- });
-
- @Override
- public IBinder onBind(Intent intent) {
- Log.d(TAG, "onBind");
- return mMessenger.getBinder();
- }
-
- private void runTest(Message msg) {
- Log.d(TAG, "runTest");
- IBinder harnessBinder = msg.getData().getBinder(REPLY_BINDER_NAME);
- Messenger harness = new Messenger(harnessBinder);
-
- try {
- Log.d(TAG, "Send MSG_TEST_STARTED");
- harness.send(Message.obtain(null, SeccompBpfTest.MSG_TEST_STARTED));
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to MSG_TEST_STARTED: " + e.getMessage());
- }
-
- demuxTest(msg.getData().getInt(RUN_TEST_IDENTIFIER));
-
- try {
- Log.d(TAG, "Send MSG_TEST_ENDED_CLEAN");
- harness.send(Message.obtain(null, SeccompBpfTest.MSG_TEST_ENDED_CLEAN));
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to MSG_TEST_ENDED_CLEAN: " + e.getMessage());
- }
- }
-
- private void demuxTest(int testNumber) {
- switch (testNumber) {
- case TEST_DEATH_TEST:
- testDeath();
- break;
- case TEST_CLEAN_TEST:
- break;
- case TEST_SIGSYS_SELF:
- testSigSysSelf();
- break;
- default:
- throw new RuntimeException("Unknown test number " + testNumber);
- }
- }
-
- public void testDeath() {
- String s = null;
- s.hashCode();
- }
-
- public native void testSigSysSelf();
-}
diff --git a/tests/tests/telecom/src/android/telecom/cts/DefaultDialerOperationsTest.java b/tests/tests/telecom/src/android/telecom/cts/DefaultDialerOperationsTest.java
index 1c6e9b1..b574a96 100644
--- a/tests/tests/telecom/src/android/telecom/cts/DefaultDialerOperationsTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/DefaultDialerOperationsTest.java
@@ -37,12 +37,23 @@
private TelecomManager mTelecomManager;
private PhoneAccountHandle mPhoneAccountHandle;
private String mPreviousDefaultDialer = null;
+ private String mSystemDialer = null;
@Override
protected void setUp() throws Exception {
super.setUp();
mContext = getInstrumentation().getContext();
+
+ if (!TestUtils.shouldTestTelecom(mContext)) {
+ return;
+ }
mPreviousDefaultDialer = TestUtils.getDefaultDialer(getInstrumentation());
+ // Reset the current dialer to the system dialer, to ensure that we start each test
+ // without being the default dialer.
+ mSystemDialer = TestUtils.getSystemDialer(getInstrumentation());
+ if (!TextUtils.isEmpty(mSystemDialer)) {
+ TestUtils.setDefaultDialer(getInstrumentation(), mSystemDialer);
+ }
mTelecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
final List<PhoneAccountHandle> accounts = mTelecomManager.getCallCapablePhoneAccounts();
if (accounts != null && !accounts.isEmpty()) {
@@ -53,18 +64,26 @@
@Override
protected void tearDown() throws Exception {
if (!TextUtils.isEmpty(mPreviousDefaultDialer)) {
+ // Restore the default dialer to whatever the default dialer was before the tests
+ // were started. This may or may not be the system dialer.
TestUtils.setDefaultDialer(getInstrumentation(), mPreviousDefaultDialer);
}
super.tearDown();
}
public void testGetDefaultDialerPackage() throws Exception {
- assertEquals(mPreviousDefaultDialer, mTelecomManager.getDefaultDialerPackage());
+ if (!TestUtils.shouldTestTelecom(mContext)) {
+ return;
+ }
+ assertEquals(mSystemDialer, mTelecomManager.getDefaultDialerPackage());
TestUtils.setDefaultDialer(getInstrumentation(), TestUtils.PACKAGE);
assertEquals(TestUtils.PACKAGE, mTelecomManager.getDefaultDialerPackage());
}
public void testVoicemailReadWritePermissions() throws Exception {
+ if (!TestUtils.shouldTestTelecom(mContext)) {
+ return;
+ }
try {
mContext.getContentResolver().query(Voicemails.CONTENT_URI, null, null, null, null);
fail("Reading voicemails should throw SecurityException if not default Dialer");
@@ -96,6 +115,9 @@
}
public void testSilenceRingerPermissions() throws Exception {
+ if (!TestUtils.shouldTestTelecom(mContext)) {
+ return;
+ }
try {
mTelecomManager.silenceRinger();
fail("TelecomManager.silenceRinger should throw SecurityException if not default "
@@ -110,6 +132,9 @@
public void testCancelMissedCallsNotificationPermissions()
throws Exception {
+ if (!TestUtils.shouldTestTelecom(mContext)) {
+ return;
+ }
try {
mTelecomManager.cancelMissedCallsNotification();
fail("TelecomManager.cancelMissedCallsNotification should throw SecurityException if "
@@ -124,6 +149,9 @@
public void testHandlePinMmPermissions()
throws Exception {
+ if (!TestUtils.shouldTestTelecom(mContext)) {
+ return;
+ }
try {
mTelecomManager.handleMmi("0");
fail("TelecomManager.handleMmi should throw SecurityException if not default dialer");
@@ -143,6 +171,9 @@
}
public void testGetAdnForPhoneAccountPermissions() throws Exception {
+ if (!TestUtils.shouldTestTelecom(mContext)) {
+ return;
+ }
try {
mTelecomManager.getAdnUriForPhoneAccount(mPhoneAccountHandle);
fail("TelecomManager.getAdnUriForPhoneAccount should throw SecurityException if "
@@ -156,6 +187,9 @@
}
public void testSetDefaultDialerNoDialIntent_notSupported() throws Exception {
+ if (!TestUtils.shouldTestTelecom(mContext)) {
+ return;
+ }
final PackageManager pm = mContext.getPackageManager();
final ComponentName name = new ComponentName(mContext,
"android.telecom.cts.MockDialerActivity");
diff --git a/tests/tests/telecom/src/android/telecom/cts/TestUtils.java b/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
index c72e3c2..ddc85a6 100644
--- a/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
+++ b/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
@@ -46,6 +46,8 @@
private static final String COMMAND_GET_DEFAULT_DIALER = "telecom get-default-dialer";
+ private static final String COMMAND_GET_SYSTEM_DIALER = "telecom get-system-dialer";
+
private static final String COMMAND_ENABLE = "telecom set-phone-account-enabled ";
public static boolean shouldTestTelecom(Context context) {
@@ -65,6 +67,10 @@
return executeShellCommand(instrumentation, COMMAND_GET_DEFAULT_DIALER);
}
+ public static String getSystemDialer(Instrumentation instrumentation) throws Exception {
+ return executeShellCommand(instrumentation, COMMAND_GET_SYSTEM_DIALER);
+ }
+
public static void enablePhoneAccount(Instrumentation instrumentation,
PhoneAccountHandle handle) throws Exception {
final ComponentName component = handle.getComponentName();
diff --git a/tests/tests/telecom2/src/android/telecom/cts/DefaultDialerOperationsNoPermissionsTest.java b/tests/tests/telecom2/src/android/telecom/cts/DefaultDialerOperationsNoPermissionsTest.java
index 4629992..86f850e 100644
--- a/tests/tests/telecom2/src/android/telecom/cts/DefaultDialerOperationsNoPermissionsTest.java
+++ b/tests/tests/telecom2/src/android/telecom/cts/DefaultDialerOperationsNoPermissionsTest.java
@@ -28,25 +28,40 @@
private Context mContext;
private TelecomManager mTelecomManager;
private String mPreviousDefaultDialer = null;
+ private String mSystemDialer = null;
@Override
protected void setUp() throws Exception {
super.setUp();
mContext = getInstrumentation().getContext();
+ if (!TestUtils.shouldTestTelecom(mContext)) {
+ return;
+ }
TestUtils.PACKAGE = mContext.getPackageName();
mPreviousDefaultDialer = TestUtils.getDefaultDialer(getInstrumentation());
+ // Reset the current dialer to the system dialer, to ensure that we start each test
+ // without being the default dialer.
+ mSystemDialer = TestUtils.getSystemDialer(getInstrumentation());
+ if (!TextUtils.isEmpty(mSystemDialer)) {
+ TestUtils.setDefaultDialer(getInstrumentation(), mSystemDialer);
+ }
mTelecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
}
@Override
protected void tearDown() throws Exception {
if (!TextUtils.isEmpty(mPreviousDefaultDialer)) {
+ // Restore the default dialer to whatever the default dialer was before the tests
+ // were started. This may or may not be the system dialer.
TestUtils.setDefaultDialer(getInstrumentation(), mPreviousDefaultDialer);
}
super.tearDown();
}
public void testShowInCallScreenPermissions() throws Exception {
+ if (!TestUtils.shouldTestTelecom(mContext)) {
+ return;
+ }
verifyForReadPhoneStateOrDefaultDialer(new Runnable() {
@Override
public void run() {
@@ -56,6 +71,9 @@
}
public void testGetCallCapableAccountsPermissions() throws Exception {
+ if (!TestUtils.shouldTestTelecom(mContext)) {
+ return;
+ }
verifyForReadPhoneStateOrDefaultDialer(new Runnable() {
@Override
public void run() {
@@ -65,6 +83,9 @@
}
public void testGetDefaultOutgoingPhoneAccount() throws Exception {
+ if (!TestUtils.shouldTestTelecom(mContext)) {
+ return;
+ }
verifyForReadPhoneStateOrDefaultDialer(new Runnable() {
@Override
public void run() {
@@ -74,6 +95,9 @@
}
public void testGetLine1Number() throws Exception {
+ if (!TestUtils.shouldTestTelecom(mContext)) {
+ return;
+ }
verifyForReadPhoneStateOrDefaultDialer(new Runnable() {
@Override
public void run() {
@@ -83,6 +107,9 @@
}
public void testGetVoicemailNumber() throws Exception {
+ if (!TestUtils.shouldTestTelecom(mContext)) {
+ return;
+ }
verifyForReadPhoneStateOrDefaultDialer(new Runnable() {
@Override
public void run() {
@@ -92,6 +119,9 @@
}
public void testIsInCall() throws Exception {
+ if (!TestUtils.shouldTestTelecom(mContext)) {
+ return;
+ }
verifyForReadPhoneStateOrDefaultDialer(new Runnable() {
@Override
public void run() {
diff --git a/tests/tests/telephony/src/android/telephony/cts/PhoneStateListenerTest.java b/tests/tests/telephony/src/android/telephony/cts/PhoneStateListenerTest.java
index f0f977a..18aa23f 100644
--- a/tests/tests/telephony/src/android/telephony/cts/PhoneStateListenerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/PhoneStateListenerTest.java
@@ -22,6 +22,7 @@
import android.telephony.CellLocation;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.net.ConnectivityManager;
import android.test.InstrumentationTestCase;
@@ -40,6 +41,7 @@
private boolean mOnMessageWaitingIndicatorChangedCalled;
private boolean mOnServiceStateChangedCalled;
private boolean mOnSignalStrengthChangedCalled;
+ private SignalStrength mSignalStrength;
private TelephonyManager mTelephonyManager;
private PhoneStateListener mListener;
private final Object mLock = new Object();
@@ -152,6 +154,54 @@
assertTrue(mOnSignalStrengthChangedCalled);
}
+ public void testOnSignalStrengthsChanged() throws Throwable {
+ if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
+ Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+ return;
+ }
+
+ TestThread t = new TestThread(new Runnable() {
+ public void run() {
+ Looper.prepare();
+
+ mListener = new PhoneStateListener() {
+ @Override
+ public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+ synchronized(mLock) {
+ mSignalStrength = signalStrength;
+ mLock.notify();
+ }
+ }
+ };
+ mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
+
+ Looper.loop();
+ }
+ });
+
+ assertTrue(mSignalStrength == null);
+ t.start();
+
+ synchronized (mLock) {
+ while(mSignalStrength == null) {
+ mLock.wait();
+ }
+ }
+ t.checkException();
+ assertTrue(mSignalStrength != null);
+
+ // Call SignalStrength methods to make sure they do not throw any exceptions
+ mSignalStrength.getCdmaDbm();
+ mSignalStrength.getCdmaEcio();
+ mSignalStrength.getEvdoDbm();
+ mSignalStrength.getEvdoEcio();
+ mSignalStrength.getEvdoSnr();
+ mSignalStrength.getGsmBitErrorRate();
+ mSignalStrength.getGsmSignalStrength();
+ mSignalStrength.isGsm();
+ mSignalStrength.getLevel();
+ }
+
public void testOnMessageWaitingIndicatorChanged() throws Throwable {
if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
diff --git a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
index 2be1dcb..ce3fe78 100644
--- a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
@@ -160,7 +160,28 @@
mTelephonyManager.getNeighboringCellInfo();
mTelephonyManager.isNetworkRoaming();
mTelephonyManager.getDeviceId();
+ mTelephonyManager.getDeviceId(mTelephonyManager.getDefaultSim());
mTelephonyManager.getDeviceSoftwareVersion();
+ mTelephonyManager.getPhoneCount();
+ }
+
+ /**
+ * Tests that the phone count returned is valid.
+ */
+ public void testGetPhoneCount() {
+ int phoneCount = mTelephonyManager.getPhoneCount();
+ int phoneType = mTelephonyManager.getPhoneType();
+ switch (phoneType) {
+ case TelephonyManager.PHONE_TYPE_GSM:
+ case TelephonyManager.PHONE_TYPE_CDMA:
+ assertTrue("Phone count should be > 0", phoneCount > 0);
+ break;
+ case TelephonyManager.PHONE_TYPE_NONE:
+ assertTrue("Phone count should be 0", phoneCount == 0);
+ break;
+ default:
+ throw new IllegalArgumentException("Did you add a new phone type? " + phoneType);
+ }
}
/**
@@ -170,6 +191,24 @@
*/
public void testGetDeviceId() {
String deviceId = mTelephonyManager.getDeviceId();
+ verifyDeviceId(deviceId);
+ }
+
+ /**
+ * Tests that the device properly reports either a valid IMEI if
+ * GSM, a valid MEID or ESN if CDMA, or a valid MAC address if
+ * only a WiFi device.
+ */
+ public void testGetDeviceIdForSlotId() {
+ String deviceId = mTelephonyManager.getDeviceId(mTelephonyManager.getDefaultSim());
+ verifyDeviceId(deviceId);
+ // Also verify that no exception is thrown for any slot id (including invalid ones)
+ for (int i = -1; i <= mTelephonyManager.getPhoneCount(); i++) {
+ mTelephonyManager.getDeviceId(i);
+ }
+ }
+
+ private void verifyDeviceId(String deviceId) {
int phoneType = mTelephonyManager.getPhoneType();
switch (phoneType) {
case TelephonyManager.PHONE_TYPE_GSM:
diff --git a/tests/tests/text/src/android/text/cts/SpannableStringBuilderTest.java b/tests/tests/text/src/android/text/cts/SpannableStringBuilderTest.java
index 4895ca9..36b081c 100644
--- a/tests/tests/text/src/android/text/cts/SpannableStringBuilderTest.java
+++ b/tests/tests/text/src/android/text/cts/SpannableStringBuilderTest.java
@@ -18,10 +18,12 @@
import android.test.AndroidTestCase;
+import android.text.Editable;
import android.text.InputFilter;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
+import android.text.TextWatcher;
import android.text.style.StrikethroughSpan;
import android.text.style.TabStopSpan;
import android.text.style.UnderlineSpan;
@@ -596,4 +598,46 @@
// expected exception
}
}
+
+ private static class MockTextWatcher implements TextWatcher {
+ private int mDepth = 0;
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ SpannableStringBuilder builder = (SpannableStringBuilder)s;
+ mDepth++;
+ assertEquals(mDepth, builder.getTextWatcherDepth());
+ mDepth--;
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ SpannableStringBuilder builder = (SpannableStringBuilder)s;
+ mDepth++;
+ assertEquals(mDepth, builder.getTextWatcherDepth());
+ mDepth--;
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ SpannableStringBuilder builder = (SpannableStringBuilder)s;
+ mDepth++;
+ assertEquals(mDepth, builder.getTextWatcherDepth());
+ if (mDepth <= builder.length()) {
+ // This will recursively call afterTextChanged.
+ builder.replace(mDepth - 1, mDepth, "a");
+ }
+ mDepth--;
+ }
+ }
+
+ public void testGetTextWatcherDepth() {
+ SpannableStringBuilder builder = new SpannableStringBuilder("hello");
+ builder.setSpan(new MockTextWatcher(), 0, builder.length(), 0);
+ assertEquals(0, builder.getTextWatcherDepth());
+ builder.replace(0, 1, "H");
+ assertEquals(0, builder.getTextWatcherDepth());
+ // MockTextWatcher replaces each character with 'a'.
+ assertEquals("aaaaa", builder.toString());
+ }
}
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
index ec02294..a52eabe 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
@@ -107,7 +107,8 @@
Log.i(LOG_TAG, String.format("Checking user agent string %s", actualUserAgentString));
final String patternString =
"Mozilla/5\\.0 \\(Linux;( U;)? Android ([^;]+);( (\\w+)-(\\w+);)?" +
- "\\s?(.*)\\sBuild/(.+)\\) AppleWebKit/(\\d+)\\.(\\d+) \\(KHTML, like Gecko\\) " +
+ "\\s?(.*)\\sBuild/(.+); wv\\) AppleWebKit/(\\d+)\\.(\\d+) " +
+ "\\(KHTML, like Gecko\\) " +
"Version/\\d+\\.\\d+ Chrome/\\d+\\.\\d+\\.\\d+\\.\\d+( Mobile)? " +
"Safari/(\\d+)\\.(\\d+)";
// Groups used:
diff --git a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
new file mode 100644
index 0000000..2dff4cb
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.widget.cts;
+
+import com.android.cts.widget.R;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.Gravity;
+import android.widget.PopupMenu;
+
+
+public class PopupMenuTest extends
+ ActivityInstrumentationTestCase2<MockPopupWindowCtsActivity> {
+ private Instrumentation mInstrumentation;
+ private Activity mActivity;
+
+ public PopupMenuTest() {
+ super("com.android.cts.widget", MockPopupWindowCtsActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mInstrumentation = getInstrumentation();
+ mActivity = getActivity();
+ }
+
+ public void testAccessGravity() {
+ PopupMenu popupMenu = new PopupMenu(mActivity,
+ mActivity.findViewById(R.id.anchor_middle_left));
+ assertEquals(Gravity.NO_GRAVITY, popupMenu.getGravity());
+ popupMenu.setGravity(Gravity.TOP);
+ assertEquals(Gravity.TOP, popupMenu.getGravity());
+ }
+
+ public void testOnDismissListener() {
+ final PopupMenu popupMenu = new PopupMenu(mActivity,
+ mActivity.findViewById(R.id.anchor_middle_left));
+ TestPopupDismissListener listener = new TestPopupDismissListener();
+ popupMenu.setOnDismissListener(listener);
+
+ mInstrumentation.runOnMainSync(new Runnable() {
+ public void run() {
+ popupMenu.show();
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ assertEquals(0, listener.getDismissCount());
+
+ mInstrumentation.runOnMainSync(new Runnable() {
+ public void run() {
+ popupMenu.dismiss();
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ assertEquals(1, listener.getDismissCount());
+
+ mInstrumentation.runOnMainSync(new Runnable() {
+ public void run() {
+ popupMenu.dismiss();
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ assertEquals(1, listener.getDismissCount());
+ }
+
+ private class TestPopupDismissListener implements PopupMenu.OnDismissListener {
+ int mDismissCount;
+
+ @Override
+ public void onDismiss(PopupMenu menu) {
+ mDismissCount++;
+ }
+
+ int getDismissCount() {
+ return mDismissCount;
+ }
+ }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/QuickContactBadgeTest.java b/tests/tests/widget/src/android/widget/cts/QuickContactBadgeTest.java
new file mode 100644
index 0000000..cfd61a2
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/QuickContactBadgeTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget.cts;
+
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
+import android.test.InstrumentationTestCase;
+import android.test.UiThreadTest;
+import android.widget.QuickContactBadge;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class QuickContactBadgeTest extends InstrumentationTestCase {
+
+ @UiThreadTest
+ public void testPrioritizedMimetype() throws InterruptedException {
+ final String plainMimeType = "text/plain";
+ final Uri nonExistentContactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 0);
+ final CountDownLatch latch = new CountDownLatch(1);
+ Context context = new ContextWrapper(getInstrumentation().getContext()) {
+ @Override
+ public void startActivity(Intent intent) {
+ testCallback(intent);
+ }
+
+ @Override
+ public void startActivityAsUser(Intent intent, UserHandle user) {
+ testCallback(intent);
+ }
+
+ @Override
+ public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) {
+ testCallback(intent);
+ }
+
+ private void testCallback(Intent intent) {
+ assertEquals(plainMimeType, intent.getStringExtra(
+ ContactsContract.QuickContact.EXTRA_PRIORITIZED_MIMETYPE));
+ latch.countDown();
+ }
+ };
+
+ // Execute: create QuickContactBadge with a prioritized mimetype and click on it
+ QuickContactBadge badge = new QuickContactBadge(context);
+ badge.setPrioritizedMimeType(plainMimeType);
+ badge.assignContactUri(nonExistentContactUri);
+ badge.onClick(badge);
+
+ // Verify: the QuickContactBadge attempts to start an activity, and sets the
+ // prioritized mimetype. We don't know which method will be used to start the activity,
+ // so we check all options.
+ assertTrue(latch.await(1, TimeUnit.SECONDS));
+ }
+}
+