Merge "remove CtsUiAutomatorTestCases" into nyc-dev
diff --git a/OldCtsTestCaseList.mk b/OldCtsTestCaseList.mk
index 070f46f..45a25f9 100644
--- a/OldCtsTestCaseList.mk
+++ b/OldCtsTestCaseList.mk
@@ -87,6 +87,7 @@
CtsAtraceTestApp \
CtsCertInstallerApp \
CtsContactDirectoryProvider \
+ CtsCustomizationApp \
CtsCppToolsApp \
CtsDeviceAdminApp23 \
CtsDeviceAdminApp24 \
diff --git a/apps/CameraITS/pymodules/its/caps.py b/apps/CameraITS/pymodules/its/caps.py
index dd35ca2..94b12f5 100644
--- a/apps/CameraITS/pymodules/its/caps.py
+++ b/apps/CameraITS/pymodules/its/caps.py
@@ -36,6 +36,19 @@
print "Test skipped"
sys.exit(SKIP_RET_CODE)
+def full_or_better(props):
+ """Returns whether a device is a FULL or better camera2 device.
+
+ Args:
+ props: Camera properties object.
+
+ Returns:
+ Boolean.
+ """
+ return props.has_key("android.info.supportedHardwareLevel") and \
+ props["android.info.supportedHardwareLevel"] != 2 and \
+ props["android.info.supportedHardwareLevel"] > 1
+
def level3(props):
"""Returns whether a device is a LEVEL3 capability camera2 device.
@@ -107,8 +120,7 @@
Boolean.
"""
return props.has_key("android.request.availableCapabilities") and \
- 1 in props["android.request.availableCapabilities"] \
- or full(props)
+ 1 in props["android.request.availableCapabilities"]
def manual_post_proc(props):
"""Returns whether a device supports MANUAL_POST_PROCESSING capabilities.
@@ -120,8 +132,7 @@
Boolean.
"""
return props.has_key("android.request.availableCapabilities") and \
- 2 in props["android.request.availableCapabilities"] \
- or full(props)
+ 2 in props["android.request.availableCapabilities"]
def raw(props):
"""Returns whether a device supports RAW capabilities.
diff --git a/apps/CameraITS/pymodules/its/device.py b/apps/CameraITS/pymodules/its/device.py
index c669540..8dfcc27 100644
--- a/apps/CameraITS/pymodules/its/device.py
+++ b/apps/CameraITS/pymodules/its/device.py
@@ -179,6 +179,11 @@
time.sleep(duration)
print "Reboot complete"
+ # Flush logcat so following code won't be misled by previous
+ # 'ItsService ready' log.
+ _run('%s logcat -c' % (self.adb))
+ time.sleep(1)
+
# TODO: Figure out why "--user 0" is needed, and fix the problem.
_run('%s shell am force-stop --user 0 %s' % (self.adb, self.PACKAGE))
_run(('%s shell am startservice --user 0 -t text/plain '
diff --git a/apps/CameraITS/tests/scene0/test_metadata.py b/apps/CameraITS/tests/scene0/test_metadata.py
index 44663bb..2914493 100644
--- a/apps/CameraITS/tests/scene0/test_metadata.py
+++ b/apps/CameraITS/tests/scene0/test_metadata.py
@@ -36,7 +36,7 @@
print "Hardware level"
print " Legacy:", its.caps.legacy(props)
print " Limited:", its.caps.limited(props)
- print " Full:", its.caps.full(props)
+ print " Full or better:", its.caps.full_or_better(props)
print "Capabilities"
print " Manual sensor:", its.caps.manual_sensor(props)
print " Manual post-proc:", its.caps.manual_post_proc(props)
@@ -46,7 +46,7 @@
# Test: hardware level should be a valid value.
check('props.has_key("android.info.supportedHardwareLevel")')
check('props["android.info.supportedHardwareLevel"] is not None')
- check('props["android.info.supportedHardwareLevel"] in [0,1,2]')
+ check('props["android.info.supportedHardwareLevel"] in [0,1,2,3]')
full = getval('props["android.info.supportedHardwareLevel"]') == 1
manual_sensor = its.caps.manual_sensor(props)
diff --git a/apps/CameraITS/tests/scene1/test_latching.py b/apps/CameraITS/tests/scene1/test_latching.py
index 176f01b..a7da421 100644
--- a/apps/CameraITS/tests/scene1/test_latching.py
+++ b/apps/CameraITS/tests/scene1/test_latching.py
@@ -33,8 +33,7 @@
with its.device.ItsSession() as cam:
props = cam.get_camera_properties()
- its.caps.skip_unless(its.caps.full(props) and
- its.caps.per_frame_control(props))
+ its.caps.skip_unless(its.caps.full_or_better(props))
_,fmt = its.objects.get_fastest_manual_capture_settings(props)
e, s = its.target.get_target_exposure_combos(cam)["midExposureTime"]
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
index 0cf58f7..af71ebe 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
@@ -77,6 +77,7 @@
new Intent(Settings.ACTION_WIRELESS_SETTINGS),
new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD),
new Intent("android.net.vpn.SETTINGS"),
+ new Intent(Settings.ACTION_VPN_SETTINGS),
new Intent("android.settings.ACCOUNT_SYNC_SETTINGS"),
new Intent(Settings.ACTION_BATTERY_SAVER_SETTINGS),
new Intent("android.settings.LICENSE"),
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/ScopedDirectoryAccessClientTest.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/ScopedDirectoryAccessClientTest.java
index 0336211..a4d35fb 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/ScopedDirectoryAccessClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/ScopedDirectoryAccessClientTest.java
@@ -85,23 +85,31 @@
openExternalDirectoryInvalidPath(volume, "/../");
openExternalDirectoryInvalidPath(volume, "/HiddenStuff");
}
+ openExternalDirectoryInvalidPath(getPrimaryVolume(), DIRECTORY_ROOT);
}
public void testUserRejects() throws Exception {
if (!supportedHardware()) return;
- final StorageVolume primaryVolume = getPrimaryVolume();
-
- // Tests user clicking DENY button, for all valid directories.
- for (String dir : STANDARD_DIRECTORIES) {
- final UiAlertDialog dialog = openExternalDirectoryValidPath(primaryVolume, dir);
- dialog.noButton.click();
+ for (StorageVolume volume : getVolumes()) {
+ // Tests user clicking DENY button, for all valid directories.
+ for (String dir : STANDARD_DIRECTORIES) {
+ userRejectsTest(volume, dir);
+ }
+ if (!volume.isPrimary()) {
+ // Also test root
+ userRejectsTest(volume, DIRECTORY_ROOT);
+ }
+ // Also test user clicking back button - one directory is enough.
+ openExternalDirectoryValidPath(volume, DIRECTORY_PICTURES);
+ mDevice.pressBack();
assertActivityFailed();
}
+ }
- // Also test user clicking back button - one directory is enough.
- openExternalDirectoryValidPath(primaryVolume, DIRECTORY_ROOT);
- mDevice.pressBack();
+ private void userRejectsTest(StorageVolume volume, String dir) throws Exception {
+ final UiAlertDialog dialog = openExternalDirectoryValidPath(volume, dir);
+ dialog.noButton.click();
assertActivityFailed();
}
@@ -110,7 +118,9 @@
for (StorageVolume volume : getVolumes()) {
userAcceptsOpenExternalDirectoryTest(volume, DIRECTORY_PICTURES);
- userAcceptsOpenExternalDirectoryTest(volume, DIRECTORY_ROOT);
+ if (!volume.isPrimary()) {
+ userAcceptsOpenExternalDirectoryTest(volume, DIRECTORY_ROOT);
+ }
}
}
@@ -149,7 +159,8 @@
public void testNotAskedAgainOnRoot() throws Exception {
if (!supportedHardware()) return;
- for (StorageVolume volume : getVolumes()) {
+ for (StorageVolume volume : getVolumes()) {
+ if (volume.isPrimary()) continue;
final String volumeDesc = volume.getDescription(getInstrumentation().getContext());
final Uri grantedRootUri = userAcceptsOpenExternalDirectoryTest(volume, DIRECTORY_ROOT);
@@ -176,9 +187,10 @@
public void testDeniesOnceButAllowsAskingAgain() throws Exception {
if (!supportedHardware())return;
- final String[] dirs = {DIRECTORY_DCIM, DIRECTORY_ROOT};
+ final String[] dirs = { DIRECTORY_DCIM, DIRECTORY_ROOT };
for (StorageVolume volume : getVolumes()) {
for (String dir : dirs) {
+ if (volume.isPrimary() && dir == DIRECTORY_ROOT) continue;
// Rejects the first attempt...
UiAlertDialog dialog = openExternalDirectoryValidPath(volume, dir);
dialog.assertDoNotAskAgainVisibility(false);
@@ -203,6 +215,7 @@
final String[] dirs = {DIRECTORY_PICTURES, DIRECTORY_ROOT};
for (StorageVolume volume : getVolumes()) {
for (String dir : dirs) {
+ if (volume.isPrimary() && dir == DIRECTORY_ROOT) continue;
// Rejects the first attempt...
UiAlertDialog dialog = openExternalDirectoryValidPath(volume, dir);
dialog.assertDoNotAskAgainVisibility(false);
@@ -234,10 +247,16 @@
final UiAlertDialog dialog = openExternalDirectoryValidPath(volume, directoryName);
final String message = dialog.messageText.getText();
Log.v(TAG, "request permission message: " + message);
- final Context context = getInstrumentation().getTargetContext();
+ final Context context = getInstrumentation().getContext();
final String appLabel = context.getPackageManager().getApplicationLabel(
context.getApplicationInfo()).toString();
assertContainsRegex("missing app label", appLabel, message);
+ final String volumeLabel = volume.getDescription(context);
+ if (volume.isPrimary()) {
+ assertNotContainsRegex("should not have volume label on primary", volumeLabel, message);
+ } else {
+ assertContainsRegex("missing volume label", volumeLabel, message);
+ }
if (directoryName != null) {
assertContainsRegex("missing folder", directoryName, message);
} else {
@@ -248,13 +267,13 @@
dialog.yesButton.click();
// ...and get its response.
- final String volumeDesc = volume.getDescription(getInstrumentation().getContext());
+ final String volumeDesc = volume.getDescription(context);
final Intent data = assertActivitySucceeded("should have already granted "
+ "permission to " + volumeDesc + " and " + directoryName);
final Uri grantedUri = data.getData();
// Test granted permission directly by persisting it...
- final ContentResolver resolver = getInstrumentation().getContext().getContentResolver();
+ final ContentResolver resolver = context.getContentResolver();
final int modeFlags = data.getFlags()
& (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
@@ -283,9 +302,10 @@
return grantedUri;
}
- private void openExternalDirectoryInvalidPath(StorageVolume volume, String path) {
- sendOpenExternalDirectoryIntent(volume, path);
- assertActivityFailed();
+ private void openExternalDirectoryInvalidPath(StorageVolume volume, String directoryName) {
+ final Intent intent = volume.createAccessIntent(directoryName);
+ assertNull("should not get intent for volume '" + volume + "' and directory '"
+ + directoryName + "'", intent);
}
private UiAlertDialog openExternalDirectoryValidPath(StorageVolume volume, String path)
@@ -296,6 +316,7 @@
private void sendOpenExternalDirectoryIntent(StorageVolume volume, String directoryName) {
final Intent intent = volume.createAccessIntent(directoryName);
+ assertNotNull("no intent for '" + volume + "' and directory " + directoryName, intent);
mActivity.startActivityForResult(intent, REQUEST_CODE);
mDevice.waitForIdle();
}
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
index abe8bf0..d968863 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
@@ -142,6 +142,15 @@
return paths;
}
+ public static List<File> getAllPackageSpecificPathsExceptMedia(Context context) {
+ final List<File> paths = new ArrayList<File>();
+ Collections.addAll(paths, context.getExternalCacheDirs());
+ Collections.addAll(paths, context.getExternalFilesDirs(null));
+ Collections.addAll(paths, context.getExternalFilesDirs(Environment.DIRECTORY_PICTURES));
+ Collections.addAll(paths, context.getObbDirs());
+ return paths;
+ }
+
public static List<File> getAllPackageSpecificPathsExceptObb(Context context) {
final List<File> paths = new ArrayList<File>();
Collections.addAll(paths, context.getExternalCacheDirs());
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
index ea6c0ea..0436252 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
@@ -17,6 +17,7 @@
package com.android.cts.writeexternalstorageapp;
import static android.test.MoreAsserts.assertNotEqual;
+
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_NONE;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.TAG;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoWriteAccess;
@@ -24,7 +25,7 @@
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadWriteAccess;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.buildProbeFile;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.deleteContents;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificPaths;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificPathsExceptMedia;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getMountPaths;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getPrimaryPackageSpecificPaths;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getSecondaryPackageSpecificPaths;
@@ -240,10 +241,10 @@
* Verify that .nomedia is created correctly.
*/
public void testVerifyNoMediaCreated() throws Exception {
- for (File file : getAllPackageSpecificPaths(getContext())) {
+ for (File file : getAllPackageSpecificPathsExceptMedia(getContext())) {
deleteContents(file);
}
- final List<File> paths = getAllPackageSpecificPaths(getContext());
+ final List<File> paths = getAllPackageSpecificPathsExceptMedia(getContext());
// Require that .nomedia was created somewhere above each dir
for (File path : paths) {
diff --git a/hostsidetests/devicepolicy/app/CustomizationApp/Android.mk b/hostsidetests/devicepolicy/app/CustomizationApp/Android.mk
new file mode 100644
index 0000000..7b29bd4
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CustomizationApp/Android.mk
@@ -0,0 +1,33 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_PACKAGE_NAME := CtsCustomizationApp
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ctsdeviceutil
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/CustomizationApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/CustomizationApp/AndroidManifest.xml
new file mode 100644
index 0000000..f638adf
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CustomizationApp/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.customizationapp">
+
+ <uses-sdk android:minSdkVersion="24"/>
+
+ <uses-permission android:name="android.permission.SET_WALLPAPER" />
+
+ <application>
+ </application>
+
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.cts.customizationapp"
+ android:label="Customization CTS Tests" />
+
+</manifest>
diff --git a/hostsidetests/devicepolicy/app/CustomizationApp/res/raw/wallpaper.png b/hostsidetests/devicepolicy/app/CustomizationApp/res/raw/wallpaper.png
new file mode 100644
index 0000000..6a2f3ba
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CustomizationApp/res/raw/wallpaper.png
Binary files differ
diff --git a/hostsidetests/devicepolicy/app/CustomizationApp/src/com/android/cts/customizationapp/CustomizationTest.java b/hostsidetests/devicepolicy/app/CustomizationApp/src/com/android/cts/customizationapp/CustomizationTest.java
new file mode 100644
index 0000000..11d8c78
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CustomizationApp/src/com/android/cts/customizationapp/CustomizationTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.customizationapp;
+
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.os.UserManager;
+import android.test.AndroidTestCase;
+
+import android.cts.util.BitmapUtils;
+import com.android.cts.customizationapp.R;
+
+/**
+ * Test class to check different restrictions, that are connected to the device customization.
+ * The test verifies that non-admin app can't circumvent restriction. The tested restriction is
+ * {@link UserManager#DISALLOW_SET_WALLPAPER}. There is no non-admin API for setting the user icon,
+ * that would allow to test {@link UserManager#DISALLOW_SET_USER_ICON} restriction in this test.
+ */
+public class CustomizationTest extends AndroidTestCase {
+ private static final int WAITING_TIME_MS = 3 * 1000;
+
+ public void testSetWallpaper_disallowed() throws Exception {
+ final WallpaperManager wallpaperManager = WallpaperManager.getInstance(mContext);
+ final Bitmap originalWallpaper = BitmapUtils.getWallpaperBitmap(mContext);
+ final Bitmap referenceWallpaper = BitmapUtils.generateRandomBitmap(97, 73);
+ final UserManager userManager =
+ (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ assertTrue(userManager.hasUserRestriction(UserManager.DISALLOW_SET_WALLPAPER));
+
+ // Checking setBitmap() method.
+ wallpaperManager.setBitmap(referenceWallpaper);
+ Thread.sleep(WAITING_TIME_MS);
+ Bitmap newWallpaper = BitmapUtils.getWallpaperBitmap(mContext);
+ assertTrue(BitmapUtils.compareBitmaps(newWallpaper, originalWallpaper));
+
+ // Checking setStream() method.
+ wallpaperManager.setStream(BitmapUtils.bitmapToInputStream(referenceWallpaper));
+ Thread.sleep(WAITING_TIME_MS);
+ newWallpaper = BitmapUtils.getWallpaperBitmap(mContext);
+ assertTrue(BitmapUtils.compareBitmaps(newWallpaper, originalWallpaper));
+
+ // Checking setResource() method.
+ wallpaperManager.setResource(R.raw.wallpaper);
+ Thread.sleep(WAITING_TIME_MS);
+ newWallpaper = BitmapUtils.getWallpaperBitmap(mContext);
+ assertTrue(BitmapUtils.compareBitmaps(newWallpaper, originalWallpaper));
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api23/Android.mk b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api23/Android.mk
index c104697..b1c35aa 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api23/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/api23/Android.mk
@@ -24,7 +24,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
-LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 ctstestrunner ub-uiautomator
+LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 ctsdeviceutil ctstestrunner ub-uiautomator
LOCAL_SDK_VERSION := current
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/Android.mk b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/Android.mk
index 1cacc99..7d08bc3 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/Android.mk
@@ -24,7 +24,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, ../src)
-LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 ctstestrunner ub-uiautomator
+LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 ctsdeviceutil ctstestrunner ub-uiautomator
LOCAL_SDK_VERSION := current
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
index c62af4c..5bd902c 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/latest/AndroidManifest.xml
@@ -22,6 +22,7 @@
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
+ <uses-permission android:name="android.permission.SET_WALLPAPER" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/res/raw/wallpaper.png b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/res/raw/wallpaper.png
new file mode 100644
index 0000000..6a2f3ba
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/res/raw/wallpaper.png
Binary files differ
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CustomizationRestrictionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CustomizationRestrictionsTest.java
new file mode 100644
index 0000000..ebc833b
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/CustomizationRestrictionsTest.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.deviceandprofileowner;
+
+import android.app.WallpaperManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.cts.util.BitmapUtils;
+import com.android.cts.deviceandprofileowner.R;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * These tests verify that the device / profile owner can use appropriate API for customization
+ * (DevicePolicyManager.setUserIcon(), WallpaperManager.setBitmap(), etc.) even in case,
+ * when appropriate restrictions are set. The tested restrictions are
+ * {@link UserManager#DISALLOW_SET_WALLPAPER} and {@link UserManager#DISALLOW_SET_USER_ICON}.
+ */
+public class CustomizationRestrictionsTest extends BaseDeviceAdminTest {
+
+ private static final int BROADCAST_TIMEOUT_SEC = 3;
+
+ // Class sets/resets restriction in try-with-resources statement.
+ private class RestrictionApplicator implements Closeable {
+ private final String mRestriction;
+ RestrictionApplicator(String restriction) {
+ mRestriction = restriction;
+ mDevicePolicyManager.addUserRestriction(ADMIN_RECEIVER_COMPONENT, mRestriction);
+ }
+
+ @Override
+ public void close() throws IOException {
+ mDevicePolicyManager.clearUserRestriction(ADMIN_RECEIVER_COMPONENT, mRestriction);
+ }
+ }
+
+ // Class subscribes/unsubscribe for broadcast notification in try-with-resources statement.
+ private class BroadcastReceiverRegistrator implements Closeable {
+ private final BlockingBroadcastReceiver mReceiver;
+ public BroadcastReceiverRegistrator(String action) {
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(action);
+ mReceiver = new BlockingBroadcastReceiver();
+ mContext.registerReceiver(mReceiver, filter);
+ }
+
+ @Override
+ public void close() throws IOException {
+ mContext.unregisterReceiver(mReceiver);
+ }
+
+ public void waitForBroadcast() throws Exception {
+ mReceiver.waitForBroadcast();
+ }
+ }
+
+ private class BlockingBroadcastReceiver extends BroadcastReceiver {
+ private BlockingQueue<Integer> mQueue = new ArrayBlockingQueue<Integer> (1);
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ assertTrue(mQueue.add(0));
+ }
+
+ public void waitForBroadcast() throws Exception {
+ Integer result = mQueue.poll(BROADCAST_TIMEOUT_SEC, TimeUnit.SECONDS);
+ assertNotNull(result);
+ }
+ }
+
+ private static int getUserId() throws Exception {
+ UserHandle userHandle = Process.myUserHandle();
+ Class<?>[] noParam = {};
+ Class<?> userHandleClass = userHandle.getClass();
+ Method methodGetIdentifier = userHandleClass.getDeclaredMethod("getIdentifier", noParam);
+ return (Integer) methodGetIdentifier.invoke(userHandle, null);
+ }
+
+ private Bitmap getUserIcon() throws Exception {
+ Class<?>[] paramInt = new Class[1];
+ paramInt[0] = Integer.TYPE;
+ Class<?> umClass = mUserManager.getClass();
+ Method methodGetUserIcon = umClass.getDeclaredMethod("getUserIcon", paramInt);
+ return (Bitmap) methodGetUserIcon.invoke(mUserManager, getUserId());
+ }
+
+ public void testDisallowSetWallpaper_allowed() throws Exception {
+ final WallpaperManager wallpaperManager = WallpaperManager.getInstance(mContext);
+ final Bitmap originalWallpaper = BitmapUtils.getWallpaperBitmap(mContext);
+
+ try (
+ // Set restriction and subscribe for the broadcast.
+ final RestrictionApplicator restr =
+ new RestrictionApplicator(UserManager.DISALLOW_SET_WALLPAPER);
+ final BroadcastReceiverRegistrator bcast =
+ new BroadcastReceiverRegistrator(Intent.ACTION_WALLPAPER_CHANGED);
+ ) {
+ assertTrue(mUserManager.hasUserRestriction(UserManager.DISALLOW_SET_WALLPAPER));
+
+ // Checking setBitmap() method.
+ Bitmap referenceWallpaper = BitmapUtils.generateRandomBitmap(97, 73);
+ wallpaperManager.setBitmap(referenceWallpaper);
+ bcast.waitForBroadcast();
+ Bitmap newWallpaper = BitmapUtils.getWallpaperBitmap(mContext);
+ // Violation of encapsulation if refs are equal.
+ assertNotSame(newWallpaper, referenceWallpaper);
+ assertTrue(BitmapUtils.compareBitmaps(newWallpaper, referenceWallpaper));
+
+ // Checking setStream() method.
+ referenceWallpaper = BitmapUtils.generateRandomBitmap(83, 69);
+ wallpaperManager.setStream(BitmapUtils.bitmapToInputStream(referenceWallpaper));
+ bcast.waitForBroadcast();
+ newWallpaper = BitmapUtils.getWallpaperBitmap(mContext);
+ assertTrue(BitmapUtils.compareBitmaps(newWallpaper, referenceWallpaper));
+
+ // Checking setResource() method.
+ final InputStream is = mContext.getResources().openRawResource(R.raw.wallpaper);
+ referenceWallpaper = BitmapFactory.decodeStream(is);
+ wallpaperManager.setResource(R.raw.wallpaper);
+ bcast.waitForBroadcast();
+ newWallpaper = BitmapUtils.getWallpaperBitmap(mContext);
+ assertTrue(BitmapUtils.compareBitmaps(newWallpaper, referenceWallpaper));
+ } finally {
+ wallpaperManager.setBitmap(originalWallpaper);
+ }
+ assertFalse(mUserManager.hasUserRestriction(UserManager.DISALLOW_SET_WALLPAPER));
+ }
+
+ public void testDisallowSetUserIcon_allowed() throws Exception {
+ final Bitmap originalIcon = getUserIcon();
+
+ try (
+ // Apply restriction.
+ final RestrictionApplicator restr =
+ new RestrictionApplicator(UserManager.DISALLOW_SET_USER_ICON);
+ ) {
+ assertTrue(mUserManager.hasUserRestriction(UserManager.DISALLOW_SET_USER_ICON));
+ final Bitmap randomBmp = BitmapUtils.generateRandomBitmap(17, 31);
+ mDevicePolicyManager.setUserIcon(ADMIN_RECEIVER_COMPONENT, randomBmp);
+ final Bitmap currentIcon = getUserIcon();
+ assertNotSame(randomBmp, currentIcon);
+ assertTrue(BitmapUtils.compareBitmaps(randomBmp, currentIcon));
+ } finally {
+ if (originalIcon == null) {
+ // There is no way to restore absence of an icon. Thus set white
+ // icon for esthetic reasons.
+ mDevicePolicyManager.setUserIcon(ADMIN_RECEIVER_COMPONENT,
+ BitmapUtils.generateWhiteBitmap(20, 20));
+ } else {
+ mDevicePolicyManager.setUserIcon(ADMIN_RECEIVER_COMPONENT, originalIcon);
+ }
+ }
+ assertFalse(mUserManager.hasUserRestriction(UserManager.DISALLOW_SET_USER_ICON));
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
index 87fe410..5d6d7fb 100755
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
@@ -105,8 +105,10 @@
final Certificate cert = getCertificate(FAKE_RSA_1.caCertificate);
// Install keypairs.
- assertTrue(mDevicePolicyManager.installKeyPair(getWho(), privKey, cert, grant, true));
- assertTrue(mDevicePolicyManager.installKeyPair(getWho(), privKey, cert, withhold, false));
+ assertTrue(mDevicePolicyManager.installKeyPair(getWho(), privKey, new Certificate[] {cert},
+ grant, true));
+ assertTrue(mDevicePolicyManager.installKeyPair(getWho(), privKey, new Certificate[] {cert},
+ withhold, false));
try {
// Verify only the requested key was actually granted.
assertGranted(grant, true);
@@ -130,7 +132,8 @@
final Certificate cert = getCertificate(FAKE_RSA_1.caCertificate);
// Install keypair.
- assertTrue(mDevicePolicyManager.installKeyPair(getWho(), privKey, cert, alias, true));
+ assertTrue(mDevicePolicyManager.installKeyPair(getWho(), privKey, new Certificate[] {cert},
+ alias, true));
try {
assertGranted(alias, true);
} finally {
@@ -140,7 +143,8 @@
assertGranted(alias, false);
// Install again.
- assertTrue(mDevicePolicyManager.installKeyPair(getWho(), privKey, cert, alias, false));
+ assertTrue(mDevicePolicyManager.installKeyPair(getWho(), privKey, new Certificate[] {cert},
+ alias, false));
try {
assertGranted(alias, false);
} finally {
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockScreenInfoTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockScreenInfoTest.java
index 7d7b57c..4863192 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockScreenInfoTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/LockScreenInfoTest.java
@@ -38,7 +38,7 @@
public void testEmptyStringClearsLockInfo() {
final String message = "";
- assertTrue(mDevicePolicyManager.setDeviceOwnerLockScreenInfo(getWho(), message));
+ mDevicePolicyManager.setDeviceOwnerLockScreenInfo(getWho(), message);
assertNull(mDevicePolicyManager.getDeviceOwnerLockScreenInfo());
}
@@ -78,7 +78,7 @@
* @throws AssertionError if the setting did not take effect.
*/
private void setLockInfo(String message) {
- assertTrue(mDevicePolicyManager.setDeviceOwnerLockScreenInfo(getWho(), message));
+ mDevicePolicyManager.setDeviceOwnerLockScreenInfo(getWho(), message);
assertEquals(message, mDevicePolicyManager.getDeviceOwnerLockScreenInfo());
}
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index d9e7790..ef9e741 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -26,8 +26,8 @@
/**
* Set of tests for use cases that apply to profile and device owner.
- * This class is the base class of MixedProfileOwnerTest and MixedDeviceOwnerTest and is abstract
- * to avoid running spurious tests.
+ * This class is the base class of MixedProfileOwnerTest, MixedDeviceOwnerTest and
+ * MixedManagedProfileOwnerTest and is abstract to avoid running spurious tests.
*
* NOTE: Not all tests are executed in the subclasses. Sometimes, if a test is not applicable to
* a subclass, they override it with an empty method.
@@ -85,6 +85,9 @@
private static final String ACCOUNT_TYPE
= "com.android.cts.devicepolicy.accountmanagement.account.type";
+ private static final String CUSTOMIZATION_APP_PKG = "com.android.cts.customizationapp";
+ private static final String CUSTOMIZATION_APP_APK = "CtsCustomizationApp.apk";
+
// ID of the user all tests are run as. For device owner this will be the primary user, for
// profile owner it is the user id of the created profile.
protected int mUserId;
@@ -102,6 +105,7 @@
getDevice().uninstallPackage(VPN_APP_PKG);
getDevice().uninstallPackage(INTENT_RECEIVER_PKG);
getDevice().uninstallPackage(INTENT_SENDER_PKG);
+ getDevice().uninstallPackage(CUSTOMIZATION_APP_PKG);
}
super.tearDown();
}
@@ -384,6 +388,45 @@
}
}
+ // Sets restrictions and launches non-admin app, that tries to set wallpaper.
+ // Non-admin apps must not violate any user restriction.
+ public void testSetWallpaper_disallowed() throws Exception {
+ // UserManager.DISALLOW_SET_WALLPAPER
+ final String DISALLOW_SET_WALLPAPER = "no_set_wallpaper";
+ if (!mHasFeature) {
+ return;
+ }
+
+ installAppAsUser(CUSTOMIZATION_APP_APK, mUserId);
+ try {
+ changeUserRestrictionForUser(DISALLOW_SET_WALLPAPER, COMMAND_ADD_USER_RESTRICTION,
+ mUserId);
+ assertTrue(runDeviceTestsAsUser(CUSTOMIZATION_APP_PKG, ".CustomizationTest",
+ "testSetWallpaper_disallowed", mUserId));
+ } finally {
+ changeUserRestrictionForUser(DISALLOW_SET_WALLPAPER, COMMAND_CLEAR_USER_RESTRICTION,
+ mUserId);
+ }
+ }
+
+ // Runs test with admin privileges. The test methods set all the tested restrictions
+ // inside. But these restrictions must have no effect on the device/profile owner behavior.
+ public void testDisallowSetWallpaper_allowed() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
+ executeDeviceTestMethod(".CustomizationRestrictionsTest",
+ "testDisallowSetWallpaper_allowed");
+ }
+
+ public void testDisallowSetUserIcon_allowed() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
+ executeDeviceTestMethod(".CustomizationRestrictionsTest",
+ "testDisallowSetUserIcon_allowed");
+ }
+
public void testPackageInstallUserRestrictions() throws Exception {
// UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES
final String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
index 6f93480..32110de 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
@@ -86,4 +86,9 @@
mPrimaryUserId));
}
}
+
+ @Override
+ public void testDisallowSetWallpaper_allowed() throws Exception {
+ // Managed profile doesn't have wallpaper.
+ }
}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index adaaf84..f33d434 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -25,6 +25,7 @@
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
+import android.app.ActivityManager;
import android.app.Instrumentation;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -64,6 +65,8 @@
private static final String STATUS_NETWORK_AVAILABLE_PREFIX = "NetworkAvailable:";
private static final int SECOND_IN_MS = 1000;
private static final int NETWORK_TIMEOUT_MS = 15 * SECOND_IN_MS;
+ private static final int PROCESS_STATE_FOREGROUND_SERVICE = 4;
+
// Must be higher than NETWORK_TIMEOUT_MS
private static final int ORDERED_BROADCAST_TIMEOUT_MS = NETWORK_TIMEOUT_MS * 4;
@@ -82,11 +85,12 @@
mContext = mInstrumentation.getContext();
mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
mWfm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- mUid = mContext.getPackageManager().getPackageInfo(TEST_APP2_PKG, 0).applicationInfo.uid;
- final int myUid = mContext.getPackageManager()
- .getPackageInfo(mContext.getPackageName(), 0).applicationInfo.uid;
+ mUid = getUid(TEST_APP2_PKG);
+ final int myUid = getUid(mContext.getPackageName());
- Log.d(TAG, "UIDS: test app=" + myUid + ", app2=" + mUid);
+ Log.i(TAG, "Apps status on " + getName() + ":\n"
+ + "\ttest app: uid=" + myUid + ", state=" + getProcessStateByUid(myUid) + "\n"
+ + "\tapp2: uid=" + mUid + ", state=" + getProcessStateByUid(mUid));
}
@Override
@@ -98,6 +102,10 @@
}
}
+ protected int getUid(String packageName) throws Exception {
+ return mContext.getPackageManager().getPackageUid(packageName, 0);
+ }
+
protected void assertRestrictBackgroundChangedReceived(int expectedCount) throws Exception {
assertRestrictBackgroundChangedReceived(DYNAMIC_RECEIVER, expectedCount);
assertRestrictBackgroundChangedReceived(MANIFEST_RECEIVER, 0);
@@ -158,6 +166,7 @@
}
protected void assertRestrictBackgroundStatus(int expectedApiStatus) throws Exception {
+ assertBackgroundState(); // Sanity check.
final Intent intent = new Intent(ACTION_CHECK_NETWORK);
final String resultData = sendOrderedBroadcast(intent);
final String[] resultItems = resultData.split(RESULT_SEPARATOR);
@@ -171,6 +180,7 @@
}
protected void assertBackgroundNetworkAccess(boolean expectAllowed) throws Exception {
+ assertBackgroundState(); // Sanity check.
final Intent intent = new Intent(ACTION_CHECK_NETWORK);
final String resultData = sendOrderedBroadcast(intent);
final String[] resultItems = resultData.split(RESULT_SEPARATOR);
@@ -178,6 +188,27 @@
assertNetworkStatus(expectAllowed, networkStatus);
}
+ protected final void assertBackgroundState() throws Exception {
+ final ProcessState state = getProcessStateByUid(mUid);
+ Log.v(TAG, "assertBackgroundState(): status for app2 (" + mUid + "): " + state);
+ final boolean isBackground = isBackground(state.state);
+ assertTrue("App2 is not on background state: " + state, isBackground);
+ }
+
+ protected final void assertForegroundServiceState() throws Exception {
+ final ProcessState state = getProcessStateByUid(mUid);
+ Log.v(TAG, "assertForegroundServiceState(): status for app2 (" + mUid + "): " + state);
+ assertEquals("App2 is not on foreground service state: " + state,
+ PROCESS_STATE_FOREGROUND_SERVICE, state.state);
+ }
+
+ /**
+ * Returns whether an app state should be considered "background" for restriction purposes.
+ */
+ protected boolean isBackground(int state) {
+ return state >= PROCESS_STATE_FOREGROUND_SERVICE;
+ }
+
private String getNetworkStatus(String[] resultItems) {
return resultItems.length < 2 ? null : resultItems[1];
}
@@ -357,7 +388,7 @@
* The service must run in a separate app because otherwise it would be killed every time
* {@link #runDeviceTests(String, String)} is executed.
*/
- protected void registerApp2BroadcastReceiver() throws Exception {
+ protected void registerBroadcastReceiver() throws Exception {
executeShellCommand("am startservice com.android.cts.net.hostside.app2/.MyService");
// Wait until receiver is ready.
final int maxTries = 5;
@@ -374,6 +405,11 @@
fail("app2 receiver is not ready");
}
+ protected void startForegroundService() throws Exception {
+ executeShellCommand(
+ "am startservice com.android.cts.net.hostside.app2/.MyForegroundService");
+ }
+
private String toString(int status) {
switch (status) {
case RESTRICT_BACKGROUND_STATUS_DISABLED:
@@ -386,4 +422,27 @@
return "UNKNOWN_STATUS_" + status;
}
}
+
+ private ProcessState getProcessStateByUid(int uid) throws Exception {
+ return new ProcessState(executeShellCommand("cmd activity get-uid-state " + uid));
+ }
+
+ private static class ProcessState {
+ private final String fullState;
+ final int state;
+
+ ProcessState(String fullState) {
+ this.fullState = fullState;
+ try {
+ this.state = Integer.parseInt(fullState.split(" ")[0]);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Could not parse " + fullState);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return fullState;
+ }
+ }
}
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java
index 5181057..8e83fa2 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/BatterySaverModeNonMeteredTest.java
@@ -25,7 +25,7 @@
setPowerSaveMode(false);
assertPowerSaveModeWhitelist(TEST_APP2_PKG, false); // Sanity check
- registerApp2BroadcastReceiver();
+ registerBroadcastReceiver();
}
@Override
@@ -38,6 +38,10 @@
public void testBackgroundNetworkAccess_enabled() throws Exception {
setPowerSaveMode(true);
assertBackgroundNetworkAccess(false);
+ // Make sure app is allowed if running a foreground service.
+ startForegroundService();
+ assertForegroundServiceState();
+ assertBackgroundNetworkAccess(true);
}
public void testBackgroundNetworkAccess_whitelisted() throws Exception {
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java
index 18e2b3e..6a8540a 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/BatterySaverModeTest.java
@@ -26,7 +26,7 @@
setMeteredNetwork();
setPowerSaveMode(false);
assertPowerSaveModeWhitelist(TEST_APP2_PKG, false); // Sanity check
- registerApp2BroadcastReceiver();
+ registerBroadcastReceiver();
}
@Override
@@ -39,6 +39,11 @@
public void testBackgroundNetworkAccess_enabled() throws Exception {
setPowerSaveMode(true);
assertBackgroundNetworkAccess(false);
+
+ // Make sure app is allowed if running a foreground service.
+ startForegroundService();
+ assertForegroundServiceState();
+ assertBackgroundNetworkAccess(true);
}
public void testBackgroundNetworkAccess_whitelisted() throws Exception {
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
index b9fca39..ff68090 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
@@ -20,6 +20,15 @@
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED;
+/*
+ * TODO: need to add more scenarios:
+ * - test access on foreground app
+ * - test access on foreground service app
+ * - make sure it works when app is on foreground and state is transitioned:
+ * - data saver is enabled
+ * - app is added/removed to blacklist
+ *
+ */
public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase {
@Override
@@ -28,7 +37,7 @@
setMeteredNetwork();
setRestrictBackground(false);
- registerApp2BroadcastReceiver();
+ registerBroadcastReceiver();
}
@Override
@@ -40,13 +49,13 @@
public void testGetRestrictBackgroundStatus_disabled() throws Exception {
removeRestrictBackgroundWhitelist(mUid);
- assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED);
assertRestrictBackgroundChangedReceived(0);
+ assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED);
// Sanity check: make sure status is always disabled, never whitelisted
addRestrictBackgroundWhitelist(mUid);
- assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED);
assertRestrictBackgroundChangedReceived(0);
+ assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED);
}
public void testGetRestrictBackgroundStatus_whitelisted() throws Exception {
@@ -54,40 +63,45 @@
assertRestrictBackgroundChangedReceived(1);
addRestrictBackgroundWhitelist(mUid);
- assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_WHITELISTED);
assertRestrictBackgroundChangedReceived(2);
+ assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_WHITELISTED);
}
public void testGetRestrictBackgroundStatus_enabled() throws Exception {
setRestrictBackground(true);
assertRestrictBackgroundChangedReceived(1);
+ assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED);
removeRestrictBackgroundWhitelist(mUid);
- assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED);
assertRestrictBackgroundChangedReceived(1);
+ assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED);
+
+ // Make sure app is allowed if running a foreground service.
+ assertBackgroundNetworkAccess(false);
+ startForegroundService();
+ assertForegroundServiceState();
+ assertBackgroundNetworkAccess(true);
}
public void testGetRestrictBackgroundStatus_blacklisted() throws Exception {
addRestrictBackgroundBlacklist(mUid);
assertRestrictBackgroundChangedReceived(1);
-
assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED);
- // TODO: currently whitelist is prevailing, hence remaining of the test below is disabled
- if (true) return;
-
// Make sure blacklist prevails over whitelist.
setRestrictBackground(true);
assertRestrictBackgroundChangedReceived(2);
+ assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED);
addRestrictBackgroundWhitelist(mUid);
+ assertRestrictBackgroundChangedReceived(3);
assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_ENABLED);
// Check status after removing blacklist.
removeRestrictBackgroundBlacklist(mUid);
- assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_WHITELISTED);
- assertRestrictBackgroundChangedReceived(3);
- setRestrictBackground(false);
- assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED);
assertRestrictBackgroundChangedReceived(4);
+ assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_WHITELISTED);
+ setRestrictBackground(false);
+ assertRestrictBackgroundChangedReceived(5);
+ assertRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED);
}
}
diff --git a/hostsidetests/net/app2/AndroidManifest.xml b/hostsidetests/net/app2/AndroidManifest.xml
index fa4cb43..9ce5781 100644
--- a/hostsidetests/net/app2/AndroidManifest.xml
+++ b/hostsidetests/net/app2/AndroidManifest.xml
@@ -32,6 +32,7 @@
-->
<application>
<service android:name=".MyService" android:exported="true"/>
+ <service android:name=".MyForegroundService" android:exported="true"/>
<receiver android:name=".MyBroadcastReceiver" >
<intent-filter>
diff --git a/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java b/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java
new file mode 100644
index 0000000..bbafd4c
--- /dev/null
+++ b/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyForegroundService.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.net.hostside.app2;
+
+import static com.android.cts.net.hostside.app2.Common.TAG;
+import android.R;
+import android.app.Notification;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.util.Log;
+
+/**
+ * Service used to change app state to FOREGROUND_SERVICE.
+ */
+public class MyForegroundService extends Service {
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Log.d(TAG, "MyForegroundService.onStartCommand: " + intent);
+ startForeground(42, new Notification.Builder(this)
+ .setSmallIcon(R.drawable.ic_dialog_alert) // any icon is fine
+ .build());
+ return START_STICKY;
+ }
+}
diff --git a/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyService.java b/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyService.java
index 55249f2..e6454c7 100644
--- a/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyService.java
+++ b/hostsidetests/net/app2/src/com/android/cts/net/hostside/app2/MyService.java
@@ -39,7 +39,7 @@
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
- Log.d(TAG, "onStartCommand: " + intent);
+ Log.d(TAG, "MyService.onStartCommand: " + intent);
final Context context = getApplicationContext();
final MyBroadcastReceiver myReceiver = new MyBroadcastReceiver(DYNAMIC_RECEIVER);
context.registerReceiver(myReceiver, new IntentFilter(ACTION_RECEIVER_READY));
diff --git a/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
index 2bd76e6..15a4e0a 100644
--- a/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
+++ b/hostsidetests/net/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
@@ -30,7 +30,6 @@
uninstallPackage(TEST_APP2_PKG, false);
installPackage(TEST_APP2_APK);
-
}
@Override
diff --git a/hostsidetests/security/Android.mk b/hostsidetests/security/Android.mk
index a8a07ef..1b32669 100644
--- a/hostsidetests/security/Android.mk
+++ b/hostsidetests/security/Android.mk
@@ -43,7 +43,6 @@
selinux_general_service_contexts := $(call intermediates-dir-for,ETC,general_service_contexts)/general_service_contexts
LOCAL_JAVA_RESOURCE_FILES := \
- $(HOST_OUT_EXECUTABLES)/sepolicy-analyze \
$(HOST_OUT_EXECUTABLES)/checkseapp \
$(HOST_OUT_EXECUTABLES)/checkfc \
$(selinux_general_seapp_contexts) \
@@ -58,6 +57,8 @@
selinux_neverallow_gen_data := cts/tools/selinux/SELinuxNeverallowTestFrame.py
+LOCAL_ADDITIONAL_DEPENDENCIES := $(COMPATIBILITY_TESTCASES_OUT_cts)/sepolicy-analyze
+
LOCAL_GENERATED_SOURCES := $(call local-generated-sources-dir)/android/cts/security/SELinuxNeverallowRulesTest.java
$(LOCAL_GENERATED_SOURCES) : PRIVATE_SELINUX_GENERAL_POLICY := $(selinux_general_policy)
diff --git a/hostsidetests/security/AndroidTest.xml b/hostsidetests/security/AndroidTest.xml
index e521761..0056e81 100644
--- a/hostsidetests/security/AndroidTest.xml
+++ b/hostsidetests/security/AndroidTest.xml
@@ -16,6 +16,6 @@
<configuration description="Config for the CTS Security host tests">
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="CtsSecurityHostTestCases.jar" />
- <option name="runtime-hint" value="12m13s" />
+ <option name="runtime-hint" value="32s" />
</test>
</configuration>
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index eb5f51e..222533a 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -16,12 +16,14 @@
package android.security.cts;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.CollectingOutputReceiver;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceTestCase;
import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.testtype.IDeviceTest;
import java.io.BufferedReader;
import java.io.File;
@@ -48,7 +50,7 @@
* run as the shell user to evaluate aspects of the state of SELinux on the test
* device which otherwise would not be available to a normal apk.
*/
-public class SELinuxHostTest extends DeviceTestCase {
+public class SELinuxHostTest extends DeviceTestCase implements IBuildReceiver, IDeviceTest {
private File sepolicyAnalyze;
private File checkSeapp;
@@ -69,6 +71,25 @@
*/
private ITestDevice mDevice;
+ private CompatibilityBuildHelper mHelper;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setBuild(IBuildInfo build) {
+ mHelper = new CompatibilityBuildHelper(build);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setDevice(ITestDevice device) {
+ super.setDevice(device);
+ mDevice = device;
+ }
+
private File copyResourceToTempFile(String resName) throws IOException {
InputStream is = this.getClass().getResourceAsStream(resName);
File tempFile = File.createTempFile("SELinuxHostTest", ".tmp");
@@ -86,51 +107,13 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- mDevice = getDevice();
-
- /* retrieve the sepolicy-analyze executable from jar */
- sepolicyAnalyze = copyResourceToTempFile("/sepolicy-analyze");
+ sepolicyAnalyze = new File(mHelper.getTestsDir(), "sepolicy-analyze");
sepolicyAnalyze.setExecutable(true);
- /* retrieve the checkseapp executable from jar */
- checkSeapp = copyResourceToTempFile("/checkseapp");
- checkSeapp.setExecutable(true);
-
- /* retrieve the checkfc executable from jar */
- checkFc = copyResourceToTempFile("/checkfc");
- checkFc.setExecutable(true);
-
/* obtain sepolicy file from running device */
devicePolicyFile = File.createTempFile("sepolicy", ".tmp");
devicePolicyFile.deleteOnExit();
mDevice.pullFile("/sys/fs/selinux/policy", devicePolicyFile);
-
- /* obtain seapp_contexts file from running device */
- deviceSeappFile = File.createTempFile("seapp_contexts", ".tmp");
- deviceSeappFile.deleteOnExit();
- mDevice.pullFile("/seapp_contexts", deviceSeappFile);
-
- /* obtain file_contexts.bin file from running device */
- deviceFcFile = File.createTempFile("file_contexts", ".bin");
- deviceFcFile.deleteOnExit();
- mDevice.pullFile("/file_contexts.bin", deviceFcFile);
-
- /* obtain property_contexts file from running device */
- devicePcFile = File.createTempFile("property_contexts", ".tmp");
- devicePcFile.deleteOnExit();
- mDevice.pullFile("/property_contexts", devicePcFile);
-
- /* obtain service_contexts file from running device */
- deviceSvcFile = File.createTempFile("service_contexts", ".tmp");
- deviceSvcFile.deleteOnExit();
- mDevice.pullFile("/service_contexts", deviceSvcFile);
-
- /* retrieve the AOSP *_contexts files from jar */
- aospSeappFile = copyResourceToTempFile("/general_seapp_contexts");
- aospFcFile = copyResourceToTempFile("/general_file_contexts.bin");
- aospPcFile = copyResourceToTempFile("/general_property_contexts");
- aospSvcFile = copyResourceToTempFile("/general_service_contexts");
- seappNeverAllowFile = copyResourceToTempFile("/general_seapp_neverallows");
}
/**
@@ -214,6 +197,18 @@
*/
public void testValidSeappContexts() throws Exception {
+ /* obtain seapp_contexts file from running device */
+ deviceSeappFile = File.createTempFile("seapp_contexts", ".tmp");
+ deviceSeappFile.deleteOnExit();
+ mDevice.pullFile("/seapp_contexts", deviceSeappFile);
+
+ /* retrieve the checkseapp executable from jar */
+ checkSeapp = copyResourceToTempFile("/checkseapp");
+ checkSeapp.setExecutable(true);
+
+ /* retrieve the AOSP seapp_neverallows file from jar */
+ seappNeverAllowFile = copyResourceToTempFile("/general_seapp_neverallows");
+
/* run checkseapp on seapp_contexts */
ProcessBuilder pb = new ProcessBuilder(checkSeapp.getAbsolutePath(),
"-p", devicePolicyFile.getAbsolutePath(),
@@ -260,6 +255,15 @@
* @throws Exception
*/
public void testAospSeappContexts() throws Exception {
+
+ /* obtain seapp_contexts file from running device */
+ deviceSeappFile = File.createTempFile("seapp_contexts", ".tmp");
+ deviceSeappFile.deleteOnExit();
+ mDevice.pullFile("/seapp_contexts", deviceSeappFile);
+
+ /* retrieve the AOSP seapp_contexts file from jar */
+ aospSeappFile = copyResourceToTempFile("/general_seapp_contexts");
+
assertFileStartsWith(aospSeappFile, deviceSeappFile);
}
@@ -270,6 +274,19 @@
* @throws Exception
*/
public void testAospFileContexts() throws Exception {
+
+ /* retrieve the checkfc executable from jar */
+ checkFc = copyResourceToTempFile("/checkfc");
+ checkFc.setExecutable(true);
+
+ /* obtain file_contexts.bin file from running device */
+ deviceFcFile = File.createTempFile("file_contexts", ".bin");
+ deviceFcFile.deleteOnExit();
+ mDevice.pullFile("/file_contexts.bin", deviceFcFile);
+
+ /* retrieve the AOSP file_contexts file from jar */
+ aospFcFile = copyResourceToTempFile("/general_file_contexts.bin");
+
/* run checkfc -c general_file_contexts.bin file_contexts.bin */
ProcessBuilder pb = new ProcessBuilder(checkFc.getAbsolutePath(),
"-c", aospFcFile.getAbsolutePath(),
@@ -292,6 +309,15 @@
* @throws Exception
*/
public void testAospPropertyContexts() throws Exception {
+
+ /* obtain property_contexts file from running device */
+ devicePcFile = File.createTempFile("property_contexts", ".tmp");
+ devicePcFile.deleteOnExit();
+ mDevice.pullFile("/property_contexts", devicePcFile);
+
+ /* retrieve the AOSP property_contexts file from jar */
+ aospPcFile = copyResourceToTempFile("/general_property_contexts");
+
assertFileStartsWith(aospPcFile, devicePcFile);
}
@@ -302,6 +328,15 @@
* @throws Exception
*/
public void testAospServiceContexts() throws Exception {
+
+ /* obtain service_contexts file from running device */
+ deviceSvcFile = File.createTempFile("service_contexts", ".tmp");
+ deviceSvcFile.deleteOnExit();
+ mDevice.pullFile("/service_contexts", deviceSvcFile);
+
+ /* retrieve the AOSP service_contexts file from jar */
+ aospSvcFile = copyResourceToTempFile("/general_service_contexts");
+
assertFileStartsWith(aospSvcFile, deviceSvcFile);
}
@@ -312,6 +347,15 @@
*/
public void testValidFileContexts() throws Exception {
+ /* retrieve the checkfc executable from jar */
+ checkFc = copyResourceToTempFile("/checkfc");
+ checkFc.setExecutable(true);
+
+ /* obtain file_contexts.bin file from running device */
+ deviceFcFile = File.createTempFile("file_contexts", ".bin");
+ deviceFcFile.deleteOnExit();
+ mDevice.pullFile("/file_contexts.bin", deviceFcFile);
+
/* run checkfc sepolicy file_contexts.bin */
ProcessBuilder pb = new ProcessBuilder(checkFc.getAbsolutePath(),
devicePolicyFile.getAbsolutePath(),
@@ -338,6 +382,15 @@
*/
public void testValidPropertyContexts() throws Exception {
+ /* retrieve the checkfc executable from jar */
+ checkFc = copyResourceToTempFile("/checkfc");
+ checkFc.setExecutable(true);
+
+ /* obtain property_contexts file from running device */
+ devicePcFile = File.createTempFile("property_contexts", ".tmp");
+ devicePcFile.deleteOnExit();
+ mDevice.pullFile("/property_contexts", devicePcFile);
+
/* run checkfc -p on property_contexts */
ProcessBuilder pb = new ProcessBuilder(checkFc.getAbsolutePath(),
"-p", devicePolicyFile.getAbsolutePath(),
@@ -364,6 +417,15 @@
*/
public void testValidServiceContexts() throws Exception {
+ /* retrieve the checkfc executable from jar */
+ checkFc = copyResourceToTempFile("/checkfc");
+ checkFc.setExecutable(true);
+
+ /* obtain service_contexts file from running device */
+ deviceSvcFile = File.createTempFile("service_contexts", ".tmp");
+ deviceSvcFile.deleteOnExit();
+ mDevice.pullFile("/service_contexts", deviceSvcFile);
+
/* run checkfc -s on service_contexts */
ProcessBuilder pb = new ProcessBuilder(checkFc.getAbsolutePath(),
"-s", devicePolicyFile.getAbsolutePath(),
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/AutoEnterPipActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/AutoEnterPipActivity.java
index dbd92b5..97bc041 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/AutoEnterPipActivity.java
+++ b/hostsidetests/services/activitymanager/app/src/android/server/app/AutoEnterPipActivity.java
@@ -22,6 +22,6 @@
@Override
protected void onResume() {
super.onResume();
- enterPictureInPicture();
+ enterPictureInPictureMode();
}
}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchPipOnPipActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchPipOnPipActivity.java
index dba7cde..d7b4cc1 100644
--- a/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchPipOnPipActivity.java
+++ b/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchPipOnPipActivity.java
@@ -20,8 +20,8 @@
public class LaunchPipOnPipActivity extends Activity {
@Override
- public void onPictureInPictureChanged(boolean inPictureInPicture) {
- super.onPictureInPictureChanged(inPictureInPicture);
+ public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
+ super.onPictureInPictureModeChanged(isInPictureInPictureMode);
AlwaysFocusablePipActivity.launchAlwaysFocusablePipActivity(this);
}
}
diff --git a/hostsidetests/theme/app/src/android/theme/app/GenerateImagesActivity.java b/hostsidetests/theme/app/src/android/theme/app/GenerateImagesActivity.java
index d0e7fc8..1bf4da1 100644
--- a/hostsidetests/theme/app/src/android/theme/app/GenerateImagesActivity.java
+++ b/hostsidetests/theme/app/src/android/theme/app/GenerateImagesActivity.java
@@ -30,7 +30,9 @@
import android.view.WindowManager.LayoutParams;
import java.io.File;
+import java.io.IOException;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Generates images by iterating through all themes and launching instances of
@@ -47,6 +49,8 @@
private final CountDownLatch mLatch = new CountDownLatch(1);
private File mOutputDir;
+ private File mOutputZip;
+
private int mCurrentTheme;
private String mFinishReason;
private boolean mFinishSuccess;
@@ -88,14 +92,6 @@
}.start();
}
- private void finish(String reason, boolean success) {
- mFinishSuccess = success;
- mFinishReason = reason;
-
- Log.i(TAG, (success ? "OKAY" : "FAIL") + ":" + reason);
- finish();
- }
-
public boolean isFinishSuccess() {
return mFinishSuccess;
}
@@ -146,10 +142,6 @@
public abstract void onFailure();
}
- public File getOutputDir() {
- return mOutputDir;
- }
-
/**
* Starts the activity to generate the next image.
*/
@@ -174,9 +166,8 @@
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != RESULT_OK) {
- Log.i(TAG, "FAIL:Failed to generate images for theme " + mCurrentTheme + " ("
- + data.getStringExtra(EXTRA_REASON) + ")");
- finish();
+ finish("Failed to generate images for theme " + mCurrentTheme + " ("
+ + data.getStringExtra(EXTRA_REASON) + ")", false);
return;
}
@@ -188,16 +179,47 @@
// If we ran out of themes, we're done.
if (!success) {
+ compressOutput();
+
finish("Image generation complete!", true);
}
}
+ private void compressOutput() {
+ mOutputZip = new File(mOutputDir.getParentFile(), mOutputDir.getName() + ".zip");
+
+ if (mOutputZip.exists()) {
+ // Remove any old test results.
+ mOutputZip.delete();
+ }
+
+ try {
+ ThemeTestUtils.compressDirectory(mOutputDir, mOutputZip);
+ ThemeTestUtils.deleteDirectory(mOutputDir);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void finish(String reason, boolean success) {
+ mFinishSuccess = success;
+ mFinishReason = reason;
+
+ finish();
+ }
+
+ @Override
public void finish() {
mLatch.countDown();
+
super.finish();
}
- public void waitForCompletion() throws InterruptedException {
- mLatch.await();
+ public File getOutputZip() {
+ return mOutputZip;
+ }
+
+ public boolean waitForCompletion(long timeoutMillis) throws InterruptedException {
+ return mLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
}
}
diff --git a/hostsidetests/theme/app/src/android/theme/app/ReferenceImagesTest.java b/hostsidetests/theme/app/src/android/theme/app/ReferenceImagesTest.java
index 7569252..6e0731d 100644
--- a/hostsidetests/theme/app/src/android/theme/app/ReferenceImagesTest.java
+++ b/hostsidetests/theme/app/src/android/theme/app/ReferenceImagesTest.java
@@ -25,6 +25,9 @@
*/
public class ReferenceImagesTest extends ActivityInstrumentationTestCase2<GenerateImagesActivity> {
+ /** Overall test timeout is 30 minutes. Should only take about 5. */
+ private static final int TEST_RESULT_TIMEOUT = 30 * 60 * 1000;
+
public ReferenceImagesTest() {
super(GenerateImagesActivity.class);
}
@@ -33,20 +36,12 @@
setActivityInitialTouchMode(true);
final GenerateImagesActivity activity = getActivity();
- activity.waitForCompletion();
-
+ assertTrue("Activity failed to complete within " + TEST_RESULT_TIMEOUT + " ms",
+ activity.waitForCompletion(TEST_RESULT_TIMEOUT));
assertTrue(activity.getFinishReason(), activity.isFinishSuccess());
- final File outputDir = activity.getOutputDir();
- final File outputZip = new File(outputDir.getParentFile(), outputDir.getName() + ".zip");
- if (outputZip.exists()) {
- // Remove any old test results.
- outputZip.delete();
- }
-
- ThemeTestUtils.compressDirectory(outputDir, outputZip);
- ThemeTestUtils.deleteDirectory(outputDir);
-
- assertTrue("Generated reference image ZIP", outputZip.exists());
+ final File outputZip = activity.getOutputZip();
+ assertTrue("Failed to generate reference image ZIP",
+ outputZip != null && outputZip.exists());
}
}
diff --git a/hostsidetests/theme/assets/23/560dpi.zip b/hostsidetests/theme/assets/23/560dpi.zip
index cf0a559..231b4f5 100644
--- a/hostsidetests/theme/assets/23/560dpi.zip
+++ b/hostsidetests/theme/assets/23/560dpi.zip
Binary files differ
diff --git a/hostsidetests/theme/src/android/theme/cts/ComparisonTask.java b/hostsidetests/theme/src/android/theme/cts/ComparisonTask.java
index 0e11111..c7a5d7c 100755
--- a/hostsidetests/theme/src/android/theme/cts/ComparisonTask.java
+++ b/hostsidetests/theme/src/android/theme/cts/ComparisonTask.java
@@ -18,7 +18,6 @@
import com.android.ddmlib.Log;
import com.android.ddmlib.Log.LogLevel;
-import com.android.tradefed.device.ITestDevice;
import java.awt.Color;
import java.awt.image.BufferedImage;
@@ -37,12 +36,10 @@
private static final int IMAGE_THRESHOLD = 2;
- private final ITestDevice mDevice;
private final File mExpected;
private final File mActual;
- public ComparisonTask(ITestDevice device, File expected, File actual) {
- mDevice = device;
+ public ComparisonTask(File expected, File actual) {
mExpected = expected;
mActual = actual;
}
diff --git a/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java b/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
index 9961d1f..855f74c 100644
--- a/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
+++ b/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
@@ -21,6 +21,7 @@
import com.android.ddmlib.Log;
import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.CollectingOutputReceiver;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceTestCase;
@@ -28,20 +29,16 @@
import com.android.tradefed.testtype.IAbiReceiver;
import com.android.tradefed.testtype.IBuildReceiver;
-import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.lang.String;
import java.util.HashMap;
import java.util.Map;
-import java.util.Scanner;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
@@ -58,12 +55,11 @@
private static final String GENERATED_ASSETS_ZIP = "/sdcard/cts-theme-assets.zip";
/** The class name of the main activity in the APK. */
- private static final String CLASS = "GenerateImagesActivity";
private static final String TEST_CLASS = "android.support.test.runner.AndroidJUnitRunner";
/** The command to launch the main instrumentation test. */
private static final String START_CMD = String.format(
- "am instrument -w %s/%s", APP_PACKAGE_NAME, TEST_CLASS);
+ "am instrument -w --no-window-animation %s/%s", APP_PACKAGE_NAME, TEST_CLASS);
private static final String CLEAR_GENERATED_CMD = "rm -rf %s/*.png";
private static final String STOP_CMD = String.format("am force-stop %s", APP_PACKAGE_NAME);
@@ -71,7 +67,7 @@
private static final String DENSITY_PROP_DEVICE = "ro.sf.lcd_density";
private static final String DENSITY_PROP_EMULATOR = "qemu.sf.lcd_density";
- /** Overall test timeout is 30 minutes. */
+ /** Overall test timeout is 30 minutes. Should only take about 5. */
private static final int TEST_RESULT_TIMEOUT = 30 * 60 * 1000;
/** Map of reference image names and files. */
@@ -155,9 +151,7 @@
@Override
protected void tearDown() throws Exception {
// Delete the temp files
- for (File ref : mReferences.values()) {
- ref.delete();
- }
+ mReferences.values().forEach(File::delete);
mExecutionService.shutdown();
@@ -222,7 +216,7 @@
pngOutput.flush();
pngOutput.close();
- mCompletionService.submit(new ComparisonTask(mDevice, expected, actual));
+ mCompletionService.submit(new ComparisonTask(expected, actual));
numTasks++;
} else {
Log.logAndDisplay(LogLevel.INFO, LOG_TAG,
@@ -237,85 +231,15 @@
}
private boolean generateDeviceImages() throws Exception {
- // Clear logcat
- mDevice.executeAdbCommand("logcat", "-c");
-
- // Stop any existing instances
+ // Stop any existing instances.
mDevice.executeShellCommand(STOP_CMD);
- // Start activity
- mDevice.executeShellCommand(START_CMD);
+ // Start instrumentation test.
+ final CollectingOutputReceiver receiver = new CollectingOutputReceiver();
+ mDevice.executeShellCommand(START_CMD, receiver, TEST_RESULT_TIMEOUT,
+ TimeUnit.MILLISECONDS, 0);
- final long testTimeout = System.currentTimeMillis() + TEST_RESULT_TIMEOUT;
- boolean aborted = false;
- boolean waiting = true;
- do {
- // Dump logcat.
- final String logs = mDevice.executeAdbCommand(
- "logcat", "-v", "brief", "-d", CLASS + ":I", "*:S");
-
- // Search for string.
- try (Scanner in = new Scanner(logs)) {
- while (in.hasNextLine()) {
- final CloseTimeout timeout = new CloseTimeout(in, TEST_RESULT_TIMEOUT);
- timeout.start();
- final String line = in.nextLine();
- timeout.cancel();
-
- if (line.startsWith("I/" + CLASS)) {
- final String[] lineSplit = line.split(":");
- if (lineSplit.length >= 3) {
- final String cmd = lineSplit[1].trim();
- final String arg = lineSplit[2].trim();
- switch (cmd) {
- case "FAIL":
- Log.logAndDisplay(LogLevel.WARN, LOG_TAG, line);
- Log.logAndDisplay(LogLevel.WARN, LOG_TAG,
- "Aborting! Check host logs for details.");
- aborted = true;
- // fall-through
- case "OKAY":
- waiting = false;
- break;
- }
- }
- }
- }
- }
- if (testTimeout < System.currentTimeMillis()) {
- Log.logAndDisplay(LogLevel.WARN, LOG_TAG, "Aborting! Test results took too long.");
- aborted = true;
- }
- } while (waiting && !aborted);
-
- return !aborted;
- }
-
- private static class CloseTimeout extends Thread {
- private final CountDownLatch mCancelLatch = new CountDownLatch(1);
-
- private final Closeable mCloseable;
- private final long mTimeout;
-
- public CloseTimeout(Closeable closeable, long timeout) {
- mCloseable = closeable;
- mTimeout = timeout;
- }
-
- @Override
- public void run() {
- try {
- if (!mCancelLatch.await(mTimeout, TimeUnit.MILLISECONDS)) {
- mCloseable.close();
- }
- } catch (InterruptedException | IOException e) {
- // Well, at least we tried.
- }
- }
-
- public void cancel() {
- mCancelLatch.countDown();
- }
+ return receiver.getOutput().contains("OK ");
}
private static String getDensityBucketForDevice(ITestDevice device) {
@@ -354,10 +278,6 @@
}
private static boolean checkHardwareTypeSkipTest(String hardwareTypeString) {
- if (hardwareTypeString.contains("android.hardware.type.watch")) {
- return true;
- }
-
- return false;
+ return hardwareTypeString.contains("android.hardware.type.watch");
}
}
diff --git a/libs/deviceutil/src/android/cts/util/BitmapUtils.java b/libs/deviceutil/src/android/cts/util/BitmapUtils.java
new file mode 100644
index 0000000..7234425
--- /dev/null
+++ b/libs/deviceutil/src/android/cts/util/BitmapUtils.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 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.cts.util;
+
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.Color;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.lang.reflect.Method;
+import java.util.Random;
+
+public class BitmapUtils {
+ private BitmapUtils() {}
+
+ // Compares two bitmaps by pixels.
+ public static boolean compareBitmaps(Bitmap bmp1, Bitmap bmp2) {
+ if (bmp1 == bmp2) {
+ return true;
+ }
+
+ if ((bmp1.getWidth() != bmp2.getWidth()) || (bmp1.getHeight() != bmp2.getHeight())) {
+ return false;
+ }
+
+ for (int i = 0; i < bmp1.getWidth(); i++) {
+ for (int j = 0; j < bmp1.getHeight(); j++) {
+ if (bmp1.getPixel(i, j) != bmp2.getPixel(i, j)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public static Bitmap generateRandomBitmap(int width, int height) {
+ final Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ final Random generator = new Random();
+ for (int x = 0; x < width; x++) {
+ for (int y = 0; y < height; y++) {
+ bmp.setPixel(x, y, generator.nextInt(Integer.MAX_VALUE));
+ }
+ }
+ return bmp;
+ }
+
+ public static Bitmap generateWhiteBitmap(int width, int height) {
+ final Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ for (int x = 0; x < width; x++) {
+ for (int y = 0; y < height; y++) {
+ bmp.setPixel(x, y, Color.WHITE);
+ }
+ }
+ return bmp;
+ }
+
+ public static Bitmap getWallpaperBitmap(Context context) throws Exception {
+ WallpaperManager wallpaperManager = WallpaperManager.getInstance(context);
+ Class<?> noparams[] = {};
+ Class<?> wmClass = wallpaperManager.getClass();
+ Method methodGetBitmap = wmClass.getDeclaredMethod("getBitmap", noparams);
+ return (Bitmap) methodGetBitmap.invoke(wallpaperManager, null);
+ }
+
+ public static ByteArrayInputStream bitmapToInputStream(Bitmap bmp) {
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ bmp.compress(CompressFormat.PNG, 0 /*ignored for PNG*/, bos);
+ byte[] bitmapData = bos.toByteArray();
+ return new ByteArrayInputStream(bitmapData);
+ }
+}
diff --git a/tests/app/src/android/app/cts/PipActivityTest.java b/tests/app/src/android/app/cts/PipActivityTest.java
index 3f053cb..1a10a5d 100644
--- a/tests/app/src/android/app/cts/PipActivityTest.java
+++ b/tests/app/src/android/app/cts/PipActivityTest.java
@@ -44,20 +44,20 @@
final boolean supportsPip =
mActivity.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
if (supportsPip) {
- mActivity.enterPictureInPicture();
- assertTrue(mActivity.inMultiWindow());
- assertTrue(mActivity.inPictureInPicture());
+ mActivity.enterPictureInPictureMode();
+ assertTrue(mActivity.isInMultiWindowMode());
+ assertTrue(mActivity.isInPictureInPictureMode());
} else {
boolean pipSupportDisabled = false;
try {
- mActivity.enterPictureInPicture();
+ mActivity.enterPictureInPictureMode();
} catch (IllegalStateException e) {
// Pip not supported
pipSupportDisabled = true;
}
assertTrue(pipSupportDisabled);
- assertFalse(mActivity.inMultiWindow());
- assertFalse(mActivity.inPictureInPicture());
+ assertFalse(mActivity.isInMultiWindowMode());
+ assertFalse(mActivity.isInPictureInPictureMode());
}
}
});
diff --git a/tests/app/src/android/app/cts/PipNotResizeableActivityTest.java b/tests/app/src/android/app/cts/PipNotResizeableActivityTest.java
index e2908cd..7189dc1 100644
--- a/tests/app/src/android/app/cts/PipNotResizeableActivityTest.java
+++ b/tests/app/src/android/app/cts/PipNotResizeableActivityTest.java
@@ -42,7 +42,7 @@
public void run() {
boolean pipSupportDisabled = false;
try {
- mActivity.enterPictureInPicture();
+ mActivity.enterPictureInPictureMode();
} catch (IllegalStateException e) {
// Pip not supported
pipSupportDisabled = true;
@@ -51,8 +51,8 @@
pipSupportDisabled = true;
}
assertTrue(pipSupportDisabled);
- assertFalse(mActivity.inMultiWindow());
- assertFalse(mActivity.inPictureInPicture());
+ assertFalse(mActivity.isInMultiWindowMode());
+ assertFalse(mActivity.isInPictureInPictureMode());
}
});
mInstrumentation.waitForIdleSync();
diff --git a/tests/app/src/android/app/cts/PipNotSupportedActivityTest.java b/tests/app/src/android/app/cts/PipNotSupportedActivityTest.java
index c9ce69c..e8d13dc 100644
--- a/tests/app/src/android/app/cts/PipNotSupportedActivityTest.java
+++ b/tests/app/src/android/app/cts/PipNotSupportedActivityTest.java
@@ -42,7 +42,7 @@
public void run() {
boolean pipSupportDisabled = false;
try {
- mActivity.enterPictureInPicture();
+ mActivity.enterPictureInPictureMode();
} catch (IllegalStateException e) {
// Pip not supported
pipSupportDisabled = true;
@@ -51,8 +51,8 @@
pipSupportDisabled = true;
}
assertTrue(pipSupportDisabled);
- assertFalse(mActivity.inMultiWindow());
- assertFalse(mActivity.inPictureInPicture());
+ assertFalse(mActivity.isInMultiWindowMode());
+ assertFalse(mActivity.isInPictureInPictureMode());
}
});
mInstrumentation.waitForIdleSync();
diff --git a/tests/tests/calllog/src/android/calllog/cts/CallLogBackupTest.java b/tests/tests/calllog/src/android/calllog/cts/CallLogBackupTest.java
index 695a138..56cb3da 100644
--- a/tests/tests/calllog/src/android/calllog/cts/CallLogBackupTest.java
+++ b/tests/tests/calllog/src/android/calllog/cts/CallLogBackupTest.java
@@ -61,6 +61,8 @@
private static final int CALL_START_TIME = 0;
private static final int CALL_DURATION = 2000;
private static final int TIMEOUT_BACKUP = 4000;
+ private static final String TEST_POST_DIAL_DIGITS = ";1234";
+ private static final String TEST_VIA_NUMBER = "555-1112";
private static final Pattern BMGR_ENABLED_PATTERN = Pattern.compile(
"^Backup Manager currently (enabled|disabled)$");
@@ -77,7 +79,9 @@
CallLog.Calls.PHONE_ACCOUNT_COMPONENT_NAME,
CallLog.Calls.PHONE_ACCOUNT_ID,
CallLog.Calls.DATA_USAGE,
- CallLog.Calls.FEATURES
+ CallLog.Calls.FEATURES,
+ CallLog.Calls.POST_DIAL_DIGITS,
+ CallLog.Calls.VIA_NUMBER
};
class Call {
@@ -89,6 +93,8 @@
String phoneAccountComponent;
String phoneAccountId;
int presentation;
+ String postDialDigits;
+ String viaNumber;
}
private String mCallLogBackupPackageName;
@@ -175,6 +181,8 @@
assertEquals(CALL_START_TIME, call.date);
assertEquals(CALL_DURATION, call.duration);
assertEquals(Calls.OUTGOING_TYPE, call.type);
+ assertEquals(TEST_POST_DIAL_DIGITS, call.postDialDigits);
+ assertEquals(TEST_VIA_NUMBER, call.viaNumber);
return call;
}
@@ -248,6 +256,8 @@
values.put(Calls.DATE, Long.valueOf(CALL_START_TIME));
values.put(Calls.DURATION, Long.valueOf(CALL_DURATION));
values.put(Calls.NEW, Integer.valueOf(1));
+ values.put(Calls.POST_DIAL_DIGITS, TEST_POST_DIAL_DIGITS);
+ values.put(Calls.VIA_NUMBER, TEST_VIA_NUMBER);
getContext().getContentResolver().insert(Calls.CONTENT_URI, values);
}
@@ -272,6 +282,10 @@
cursor.getColumnIndex(Calls.PHONE_ACCOUNT_ID));
call.presentation = cursor.getInt(
cursor.getColumnIndex(Calls.NUMBER_PRESENTATION));
+ call.postDialDigits = cursor.getString(
+ cursor.getColumnIndex(Calls.POST_DIAL_DIGITS));
+ call.viaNumber = cursor.getString(
+ cursor.getColumnIndex(Calls.VIA_NUMBER));
calls.add(call);
}
} finally {
diff --git a/tests/tests/keystore/Android.mk b/tests/tests/keystore/Android.mk
index 8e86c0e..66d3ebc 100644
--- a/tests/tests/keystore/Android.mk
+++ b/tests/tests/keystore/Android.mk
@@ -24,7 +24,7 @@
LOCAL_COMPATIBILITY_SUITE := cts
LOCAL_STATIC_JAVA_LIBRARIES := \
- ctstestrunner core-tests-support platform-test-annotations
+ ctstestrunner core-tests-support platform-test-annotations ctsdeviceutil
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyStoreTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyStoreTest.java
new file mode 100644
index 0000000..988f75a
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyStoreTest.java
@@ -0,0 +1,2546 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+import com.android.cts.util.TimeoutReq;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStore.Builder;
+import java.security.KeyStore.Entry;
+import java.security.KeyStore.LoadStoreParameter;
+import java.security.KeyStore.PasswordProtection;
+import java.security.KeyStore.PrivateKeyEntry;
+import java.security.KeyStore.ProtectionParameter;
+import java.security.KeyStore.SecretKeyEntry;
+import java.security.KeyStore.TrustedCertificateEntry;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.Security;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import junit.framework.TestCase;
+
+import libcore.java.security.StandardNames;
+import libcore.java.security.TestKeyStore;
+
+public class KeyStoreTest extends TestCase {
+
+ private static final HashMap<String, PrivateKeyEntry> sPrivateKeys
+ = new HashMap<String, PrivateKeyEntry>();
+
+ private static TestKeyStore sTestKeyStore;
+
+ private static final String[] KEY_TYPES = new String[] { "DH", "DSA", "RSA", "EC" };
+
+ private static PrivateKeyEntry sPrivateKey2;
+
+ private static SecretKey sSecretKey;
+ private static SecretKey sSecretKey2;
+
+ private static final String ALIAS_PRIVATE = "private";
+ private static final String ALIAS_CERTIFICATE = "certificate";
+ private static final String ALIAS_SECRET = "secret";
+
+ private static final String ALIAS_ALT_CASE_PRIVATE = "pRiVaTe";
+ private static final String ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE = "PrIvAtE-no-password";
+ private static final String ALIAS_ALT_CASE_CERTIFICATE = "cErTiFiCaTe";
+ private static final String ALIAS_ALT_CASE_SECRET = "sEcRet";
+
+ private static final String ALIAS_UNICODE_PRIVATE = "\u6400\u7902\u3101\u8c02\u5002\u8702\udd01";
+ private static final String ALIAS_UNICODE_NO_PASSWORD_PRIVATE = "\u926c\u0967\uc65b\ubc78";
+ private static final String ALIAS_UNICODE_CERTIFICATE = "\u5402\udd01\u7902\u8702\u3101\u5f02\u3101\u5402\u5002\u8702\udd01";
+ private static final String ALIAS_UNICODE_SECRET = "\ue224\ud424\ud224\ue124\ud424\ue324";
+
+ private static final String ALIAS_NO_PASSWORD_PRIVATE = "private-no-password";
+ private static final String ALIAS_NO_PASSWORD_SECRET = "secret-no-password";
+
+ private static final char[] PASSWORD_STORE = "store password".toCharArray();
+ private static final char[] PASSWORD_KEY = "key password".toCharArray();
+ private static final char[] PASSWORD_BAD = "dummy".toCharArray();
+
+ private static final ProtectionParameter PARAM_STORE = new PasswordProtection(PASSWORD_STORE);
+ private static final ProtectionParameter PARAM_KEY = new PasswordProtection(PASSWORD_KEY);
+ private static final ProtectionParameter PARAM_BAD = new PasswordProtection(PASSWORD_BAD);
+
+ private static PrivateKeyEntry getPrivateKey() {
+ return getPrivateKey("RSA");
+ }
+
+ private static PrivateKeyEntry getPrivateKey(String keyType) {
+ // Avoiding initialization of TestKeyStore in the static initializer: it breaks CTS tests
+ // by causing a NetworkOnMainThreadException.
+ if (sTestKeyStore == null) {
+ sTestKeyStore = new TestKeyStore.Builder()
+ .keyAlgorithms("RSA", "DH_RSA", "DSA", "EC")
+ .aliasPrefix("rsa-dsa-ec-dh")
+ .build();
+ }
+
+ PrivateKeyEntry entry = sPrivateKeys.get(keyType);
+ if (entry == null) {
+ if ("RSA".equals(keyType)) {
+ entry = sTestKeyStore.getPrivateKey("RSA", "RSA");
+ } else if ("DH".equals(keyType)) {
+ entry = sTestKeyStore.getPrivateKey("DH", "RSA");
+ } else if ("DSA".equals(keyType)) {
+ entry = sTestKeyStore.getPrivateKey("DSA", "DSA");
+ } else if ("EC".equals(keyType)) {
+ entry = sTestKeyStore.getPrivateKey("EC", "EC");
+ } else {
+ throw new IllegalArgumentException("Unexpected key type " + keyType);
+ }
+ sPrivateKeys.put(keyType, entry);
+ }
+ return entry;
+ }
+
+ private static PrivateKeyEntry getPrivateKey2() {
+ if (sPrivateKey2 == null) {
+ sPrivateKey2 = TestKeyStore.getClientCertificate().getPrivateKey("RSA", "RSA");
+ }
+ return sPrivateKey2;
+ }
+
+ private static SecretKey getSecretKey() {
+ if (sSecretKey == null) {
+ sSecretKey = generateSecretKey();
+ }
+ return sSecretKey;
+ }
+
+ private static SecretKey getSecretKey2() {
+ if (sSecretKey2 == null) {
+ sSecretKey2 = generateSecretKey();
+ }
+ return sSecretKey2;
+ }
+
+ private static SecretKey generateSecretKey() {
+ try {
+ KeyGenerator kg = KeyGenerator.getInstance("DES");
+ return kg.generateKey();
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static List<KeyStore> keyStores() throws Exception {
+ List<KeyStore> keyStores = new ArrayList<KeyStore>();
+ Provider[] providers = Security.getProviders();
+ for (Provider provider : providers) {
+ Set<Provider.Service> services = provider.getServices();
+ for (Provider.Service service : services) {
+ String type = service.getType();
+ if (!type.equals("KeyStore")) {
+ continue;
+ }
+ String algorithm = service.getAlgorithm();
+ KeyStore ks = KeyStore.getInstance(algorithm, provider);
+ assertEquals(provider, ks.getProvider());
+ assertEquals(algorithm, ks.getType());
+ if (!isUnsupported(ks)) {
+ keyStores.add(ks);
+ }
+ }
+ }
+ return keyStores;
+ }
+
+ private static boolean isSecretKeyEnabled(KeyStore ks) {
+ // JKS key stores cannot store secret keys, neither can the RI's PKCS12
+ return (!(ks.getType().equals("JKS")
+ || ks.getType().equals("CaseExactJKS")
+ || (ks.getType().equals("PKCS12"))
+ || (ks.getType().equals("AndroidKeyStore"))));
+ }
+
+ private static boolean isCertificateEnabled(KeyStore ks) {
+ // RI can't handle certificate in PKCS12, but BC can
+ return (!(ks.getType().equals("PKCS12") && ks.getProvider().getName().equals("SunJSSE")));
+ }
+
+ private static boolean isCaseSensitive(KeyStore ks) {
+ return (ks.getType().equals("CaseExactJKS")
+ || ks.getType().equals("BKS")
+ || ks.getType().equals("BouncyCastle")
+ || ks.getType().equals("AndroidKeyStore"));
+
+ }
+
+ private static boolean isUnsupported(KeyStore ks) {
+ // Don't bother testing BC on RI
+ // TODO enable AndroidKeyStore when CTS can set up the keystore
+ return (StandardNames.IS_RI && ks.getProvider().getName().equals("BC"))
+ || "AndroidKeyStore".equalsIgnoreCase(ks.getType())
+ || "TimaKeyStore".equalsIgnoreCase(ks.getType());
+ }
+
+ private static boolean isNullPasswordAllowed(KeyStore ks) {
+ return (!(ks.getType().equals("JKS")
+ || ks.getType().equals("CaseExactJKS")
+ || ks.getType().equals("JCEKS")
+ || ks.getType().equals("PKCS12")));
+ }
+ private static boolean isKeyPasswordSupported(KeyStore ks) {
+ return !ks.getType().equals("AndroidKeyStore");
+ }
+ private static boolean isKeyPasswordIgnored(KeyStore ks) {
+ // BouncyCastle's PKCS12 ignores the key password unlike the RI which requires it
+ return (ks.getType().equals("PKCS12") && ks.getProvider().getName().equals("BC"));
+ }
+
+ private static boolean isLoadStoreParameterSupported(KeyStore ks) {
+ // BouncyCastle's PKCS12 allows a JDKPKCS12StoreParameter
+ return (ks.getType().equals("PKCS12") && ks.getProvider().getName().equals("BC"));
+ }
+
+ private static boolean isPersistentStorage(KeyStore ks) {
+ return ks.getType().equalsIgnoreCase("AndroidKeyStore");
+ }
+
+ private static boolean isLoadStoreUnsupported(KeyStore ks) {
+ return ks.getType().equalsIgnoreCase("AndroidKeyStore");
+ }
+
+ private static boolean isSetKeyByteArrayUnimplemented(KeyStore ks) {
+ // All of BouncyCastle's
+ // KeyStore.setKeyEntry(String,byte[],char[]) implementations
+ // throw RuntimeException
+ return (ks.getProvider().getName().equals("BC"));
+ }
+
+ private static boolean hasDefaultContents(KeyStore ks) {
+ // AndroidCAStore exposes CA cert files via the KeyStore
+ // interface, so it does start out empty like other KeyStores
+ return (ks.getType().equals("AndroidCAStore"));
+ }
+
+ private static boolean isReadOnly(KeyStore ks) {
+ // AndroidCAStore is read only, throwing
+ // UnsupportedOperationException on write operations
+ return (ks.getType().equals("AndroidCAStore"));
+ }
+
+ public static void populate(KeyStore ks) throws Exception {
+ boolean readOnly = clearKeyStore(ks);
+ if (readOnly) {
+ return;
+ }
+ if (isKeyPasswordSupported(ks)) {
+ setPrivateKey(ks);
+ }
+ if (isNullPasswordAllowed(ks)) {
+ ks.setKeyEntry(ALIAS_NO_PASSWORD_PRIVATE,
+ getPrivateKey().getPrivateKey(),
+ null,
+ getPrivateKey().getCertificateChain());
+ }
+ if (isCertificateEnabled(ks)) {
+ ks.setCertificateEntry(ALIAS_CERTIFICATE,
+ getPrivateKey().getCertificate());
+ }
+ if (isSecretKeyEnabled(ks)) {
+ setSecretKey(ks);
+ if (isNullPasswordAllowed(ks)) {
+ ks.setKeyEntry(ALIAS_NO_PASSWORD_SECRET,
+ getSecretKey(),
+ null,
+ null);
+ }
+ }
+ }
+
+ private static boolean clearKeyStore(KeyStore ks) throws Exception {
+ ks.load(null, null);
+ if (isReadOnly(ks)) {
+ try {
+ setPrivateKey(ks);
+ fail(ks.toString());
+ } catch (UnsupportedOperationException e) {
+ }
+ return true;
+ }
+ if (isPersistentStorage(ks)) {
+ Enumeration<String> aliases = ks.aliases();
+ while (aliases.hasMoreElements()) {
+ String alias = aliases.nextElement();
+ ks.deleteEntry(alias);
+ }
+ }
+ return false;
+ }
+
+ public static void setPrivateKeyNoPassword(KeyStore ks, String alias, PrivateKeyEntry privateKey)
+ throws Exception {
+ ks.setKeyEntry(alias, privateKey.getPrivateKey(), null, privateKey.getCertificateChain());
+ }
+ public static void setPrivateKey(KeyStore ks) throws Exception {
+ setPrivateKey(ks, ALIAS_PRIVATE);
+ }
+ public static void setPrivateKey(KeyStore ks, String alias) throws Exception {
+ setPrivateKey(ks, alias, getPrivateKey());
+ }
+ public static void setPrivateKey(KeyStore ks,
+ String alias,
+ PrivateKeyEntry privateKey)
+ throws Exception {
+ ks.setKeyEntry(alias,
+ privateKey.getPrivateKey(),
+ PASSWORD_KEY,
+ privateKey.getCertificateChain());
+ }
+
+ public static void setPrivateKeyBytes(KeyStore ks) throws Exception {
+ setPrivateKeyBytes(ks, ALIAS_PRIVATE);
+ }
+ public static void setPrivateKeyBytes(KeyStore ks, String alias) throws Exception {
+ setPrivateKeyBytes(ks, alias, getPrivateKey());
+ }
+ public static void setPrivateKeyBytes(KeyStore ks,
+ String alias,
+ PrivateKeyEntry privateKey)
+ throws Exception {
+ ks.setKeyEntry(alias,
+ privateKey.getPrivateKey().getEncoded(),
+ privateKey.getCertificateChain());
+ }
+
+ public static void setSecretKey(KeyStore ks) throws Exception {
+ setSecretKey(ks, ALIAS_SECRET);
+ }
+ public static void setSecretKey(KeyStore ks, String alias) throws Exception {
+ setSecretKey(ks, alias, getSecretKey());
+ }
+ public static void setSecretKey(KeyStore ks, String alias, SecretKey key) throws Exception {
+ ks.setKeyEntry(alias,
+ key,
+ PASSWORD_KEY,
+ null);
+ }
+
+ public static void setSecretKeyBytes(KeyStore ks) throws Exception {
+ setSecretKeyBytes(ks, ALIAS_SECRET);
+ }
+ public static void setSecretKeyBytes(KeyStore ks, String alias) throws Exception {
+ setSecretKeyBytes(ks, alias, getSecretKey());
+ }
+ public static void setSecretKeyBytes(KeyStore ks, String alias, SecretKey key)
+ throws Exception {
+ ks.setKeyEntry(alias,
+ key.getEncoded(),
+ null);
+ }
+
+ public static void setCertificate(KeyStore ks) throws Exception {
+ setCertificate(ks, ALIAS_CERTIFICATE);
+ }
+ public static void setCertificate(KeyStore ks, String alias) throws Exception {
+ setCertificate(ks, alias, getPrivateKey().getCertificate());
+ }
+ public static void setCertificate(KeyStore ks, String alias, Certificate certificate)
+ throws Exception {
+ ks.setCertificateEntry(alias, certificate);
+ }
+
+
+ public static void assertPrivateKey(Key actual)
+ throws Exception {
+ assertEquals(getPrivateKey().getPrivateKey(), actual);
+ }
+ public static void assertPrivateKey(String keyType, Key actual)
+ throws Exception {
+ assertEquals(getPrivateKey(keyType).getPrivateKey(), actual);
+ }
+ public static void assertPrivateKey2(Key actual)
+ throws Exception {
+ assertEquals(getPrivateKey2().getPrivateKey(), actual);
+ }
+ public static void assertPrivateKey(Entry actual)
+ throws Exception {
+ assertNotNull(actual);
+ assertSame(PrivateKeyEntry.class, actual.getClass());
+ PrivateKeyEntry privateKey = (PrivateKeyEntry) actual;
+ assertEquals(getPrivateKey().getPrivateKey(), privateKey.getPrivateKey());
+ assertEquals(getPrivateKey().getCertificate(), privateKey.getCertificate());
+ assertEquals(Arrays.asList(getPrivateKey().getCertificateChain()),
+ Arrays.asList(privateKey.getCertificateChain()));
+ }
+
+ public static void assertSecretKey(Key actual)
+ throws Exception {
+ assertEquals(getSecretKey(), actual);
+ }
+ public static void assertSecretKey2(Key actual)
+ throws Exception {
+ assertEquals(getSecretKey2(), actual);
+ }
+ public static void assertSecretKey(Entry actual)
+ throws Exception {
+ assertSame(SecretKeyEntry.class, actual.getClass());
+ assertEquals(getSecretKey(), ((SecretKeyEntry) actual).getSecretKey());
+ }
+
+ public static void assertCertificate(Certificate actual)
+ throws Exception {
+ assertEquals(getPrivateKey().getCertificate(), actual);
+ }
+ public static void assertCertificate2(Certificate actual)
+ throws Exception {
+ assertEquals(getPrivateKey2().getCertificate(), actual);
+ }
+ public static void assertCertificate(Entry actual)
+ throws Exception {
+ assertSame(TrustedCertificateEntry.class, actual.getClass());
+ assertEquals(getPrivateKey().getCertificate(),
+ ((TrustedCertificateEntry) actual).getTrustedCertificate());
+ }
+
+ public static void assertCertificateChain(Certificate[] actual)
+ throws Exception {
+ assertEquals(Arrays.asList(getPrivateKey().getCertificateChain()),
+ Arrays.asList(actual));
+ }
+
+ public void test_KeyStore_create() throws Exception {
+ Provider[] providers = Security.getProviders();
+ for (Provider provider : providers) {
+ Set<Provider.Service> services = provider.getServices();
+ for (Provider.Service service : services) {
+ String type = service.getType();
+ if (!type.equals("KeyStore")) {
+ continue;
+ }
+ String algorithm = service.getAlgorithm();
+ KeyStore ks = KeyStore.getInstance(algorithm, provider);
+ assertEquals(provider, ks.getProvider());
+ assertEquals(algorithm, ks.getType());
+ }
+ }
+ }
+
+ public void test_KeyStore_getInstance() throws Exception {
+ String type = KeyStore.getDefaultType();
+ try {
+ KeyStore.getInstance(null);
+ fail(type);
+ } catch (NullPointerException expected) {
+ }
+
+ assertNotNull(KeyStore.getInstance(type));
+
+ String providerName = StandardNames.SECURITY_PROVIDER_NAME;
+ try {
+ KeyStore.getInstance(null, (String)null);
+ fail(type);
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ KeyStore.getInstance(null, providerName);
+ fail(type);
+ } catch (Exception e) {
+ if (e.getClass() != NullPointerException.class
+ && e.getClass() != KeyStoreException.class) {
+ throw e;
+ }
+ }
+ try {
+ KeyStore.getInstance(type, (String)null);
+ fail(type);
+ } catch (IllegalArgumentException expected) {
+ }
+ assertNotNull(KeyStore.getInstance(type, providerName));
+
+ Provider provider = Security.getProvider(providerName);
+ try {
+ KeyStore.getInstance(null, (Provider)null);
+ fail(type);
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ KeyStore.getInstance(null, provider);
+ fail(type);
+ } catch (NullPointerException expected) {
+ }
+ try {
+ KeyStore.getInstance(type, (Provider)null);
+ fail(type);
+ } catch (IllegalArgumentException expected) {
+ }
+ assertNotNull(KeyStore.getInstance(type, provider));
+ }
+
+ public void test_KeyStore_getDefaultType() throws Exception {
+ String type = KeyStore.getDefaultType();
+ assertNotNull(type);
+ KeyStore ks = KeyStore.getInstance(type);
+ assertNotNull(ks);
+ assertEquals(type, ks.getType());
+ }
+
+ public void test_KeyStore_getProvider() throws Exception {
+ KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+ assertNotNull(ks.getProvider());
+ assertNotNull(StandardNames.SECURITY_PROVIDER_NAME, ks.getProvider().getName());
+
+ for (KeyStore keyStore : keyStores()) {
+ assertNotNull(keyStore.getProvider());
+ }
+ }
+
+ public void test_KeyStore_getType() throws Exception {
+ String type = KeyStore.getDefaultType();
+ KeyStore ks = KeyStore.getInstance(type);
+ assertNotNull(ks.getType());
+ assertNotNull(type, ks.getType());
+
+ for (KeyStore keyStore : keyStores()) {
+ assertNotNull(keyStore.getType());
+ }
+ }
+
+ public void test_KeyStore_getKey() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ try {
+ keyStore.getKey(null, null);
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ populate(keyStore);
+
+ // test odd inputs
+ try {
+ keyStore.getKey(null, null);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != NullPointerException.class
+ && e.getClass() != IllegalArgumentException.class) {
+ throw e;
+ }
+ }
+ try {
+ keyStore.getKey(null, PASSWORD_KEY);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != NullPointerException.class
+ && e.getClass() != IllegalArgumentException.class
+ && e.getClass() != KeyStoreException.class) {
+ throw e;
+ }
+ }
+ assertNull(keyStore.getKey("", null));
+ assertNull(keyStore.getKey("", PASSWORD_KEY));
+
+ // test case sensitive
+ if (isReadOnly(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ } else {
+ if (isKeyPasswordSupported(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ }
+ if (isSecretKeyEnabled(keyStore)) {
+ assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ } else {
+ assertNull(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ }
+ }
+
+ // test case insensitive
+ if (isCaseSensitive(keyStore) || isReadOnly(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, PASSWORD_KEY));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
+ } else {
+ if (isKeyPasswordSupported(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ }
+ if (isSecretKeyEnabled(keyStore)) {
+ assertSecretKey(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
+ }
+ }
+
+ // test with null passwords
+ if (isKeyPasswordSupported(keyStore) && isKeyPasswordIgnored(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, null));
+ } else {
+ if (isReadOnly(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_PRIVATE, null));
+ } else if (isKeyPasswordSupported(keyStore)) {
+ try {
+ keyStore.getKey(ALIAS_PRIVATE, null);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != UnrecoverableKeyException.class
+ && e.getClass() != IllegalArgumentException.class) {
+ throw e;
+ }
+ }
+ }
+ }
+ if (isReadOnly(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_SECRET, null));
+ } else if (isSecretKeyEnabled(keyStore)) {
+ try {
+ keyStore.getKey(ALIAS_SECRET, null);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != UnrecoverableKeyException.class
+ && e.getClass() != IllegalArgumentException.class) {
+ throw e;
+ }
+ }
+ }
+
+ // test with bad passwords
+ if (isReadOnly(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_PRIVATE, null));
+ } else if (isKeyPasswordSupported(keyStore) && isKeyPasswordIgnored(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, null));
+ } else if (isKeyPasswordSupported(keyStore)) {
+ try {
+ keyStore.getKey(ALIAS_PRIVATE, PASSWORD_BAD);
+ fail(keyStore.getType());
+ } catch (UnrecoverableKeyException expected) {
+ }
+ }
+ if (isReadOnly(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_SECRET, PASSWORD_BAD));
+ } else if (isSecretKeyEnabled(keyStore)) {
+ try {
+ keyStore.getKey(ALIAS_SECRET, PASSWORD_BAD);
+ fail(keyStore.getType());
+ } catch (UnrecoverableKeyException expected) {
+ }
+ }
+ }
+ }
+
+ public void test_KeyStore_getCertificateChain() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ try {
+ keyStore.getCertificateChain(null);
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+ for (KeyStore keyStore : keyStores()) {
+ populate(keyStore);
+
+ // test odd inputs
+ try {
+ keyStore.getCertificateChain(null);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != NullPointerException.class
+ && e.getClass() != IllegalArgumentException.class) {
+ throw e;
+ }
+ }
+ assertNull(keyStore.getCertificateChain(""));
+
+ // test case sensitive
+ if (isReadOnly(keyStore)) {
+ assertNull(keyStore.getCertificateChain(ALIAS_PRIVATE));
+ } else if (isKeyPasswordSupported(keyStore)) {
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_PRIVATE));
+ } else if (isNullPasswordAllowed(keyStore)) {
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_NO_PASSWORD_PRIVATE));
+ }
+
+ // test case insensitive
+ if (isReadOnly(keyStore) || isCaseSensitive(keyStore)) {
+ assertNull(keyStore.getCertificateChain(ALIAS_ALT_CASE_PRIVATE));
+ } else {
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_ALT_CASE_PRIVATE));
+ }
+ }
+ }
+
+ public void test_KeyStore_getCertificate() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ try {
+ keyStore.getCertificate(null);
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+ for (KeyStore keyStore : keyStores()) {
+ populate(keyStore);
+
+ // test odd inputs
+ try {
+ keyStore.getCertificate(null);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != NullPointerException.class
+ && e.getClass() != IllegalArgumentException.class) {
+ throw e;
+ }
+ }
+ assertNull(keyStore.getCertificate(""));
+
+ // test case sensitive
+ if (!isReadOnly(keyStore) && isCertificateEnabled(keyStore)) {
+ assertCertificate(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ } else {
+ assertNull(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ }
+
+ // test case insensitive
+ if (isReadOnly(keyStore) || isCaseSensitive(keyStore)) {
+ assertNull(keyStore.getCertificate(ALIAS_ALT_CASE_CERTIFICATE));
+ } else {
+ if (isCertificateEnabled(keyStore)) {
+ assertCertificate(keyStore.getCertificate(ALIAS_ALT_CASE_CERTIFICATE));
+ }
+ }
+ }
+ }
+
+ public void test_KeyStore_getCreationDate() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ try {
+ keyStore.getCreationDate(null);
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+ long before = System.currentTimeMillis();
+ for (KeyStore keyStore : keyStores()) {
+ populate(keyStore);
+
+ // add 1000 since some key stores round of time to nearest second
+ long after = System.currentTimeMillis() + 1000;
+
+ // test odd inputs
+ try {
+ keyStore.getCreationDate(null);
+ fail(keyStore.getType());
+ } catch (NullPointerException expected) {
+ }
+ assertNull(keyStore.getCreationDate(""));
+
+ // test case sensitive
+ if (!isReadOnly(keyStore) && isCertificateEnabled(keyStore)) {
+ Date date = keyStore.getCreationDate(ALIAS_CERTIFICATE);
+ assertNotNull(date);
+ assertTrue("date should be after start time: " + date.getTime() + " >= " + before,
+ before <= date.getTime());
+ assertTrue("date should be before expiry time: " + date.getTime() + " <= " + after,
+ date.getTime() <= after);
+ } else {
+ assertNull(keyStore.getCreationDate(ALIAS_CERTIFICATE));
+ }
+
+ // test case insensitive
+ if (isReadOnly(keyStore) || isCaseSensitive(keyStore)) {
+ assertNull(keyStore.getCreationDate(ALIAS_ALT_CASE_CERTIFICATE));
+ } else {
+ if (isCertificateEnabled(keyStore)) {
+ Date date = keyStore.getCreationDate(ALIAS_ALT_CASE_CERTIFICATE);
+ assertTrue(before <= date.getTime());
+ assertTrue(date.getTime() <= after);
+ }
+ }
+ }
+ }
+
+ public void test_KeyStore_setKeyEntry_Key() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ try {
+ keyStore.setKeyEntry(null, null, null, null);
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null, null);
+ if (isReadOnly(keyStore)) {
+ try {
+ keyStore.setKeyEntry(null, null, null, null);
+ fail(keyStore.getType());
+ } catch (UnsupportedOperationException expected) {
+ }
+ continue;
+ }
+
+ // test odd inputs
+ try {
+ keyStore.setKeyEntry(null, null, null, null);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != NullPointerException.class
+ && e.getClass() != KeyStoreException.class) {
+ throw e;
+ }
+ }
+ try {
+ keyStore.setKeyEntry(null, null, PASSWORD_KEY, null);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != NullPointerException.class
+ && e.getClass() != KeyStoreException.class) {
+ throw e;
+ }
+ }
+ try {
+ keyStore.setKeyEntry(ALIAS_PRIVATE,
+ getPrivateKey().getPrivateKey(),
+ PASSWORD_KEY,
+ null);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != IllegalArgumentException.class
+ && e.getClass() != KeyStoreException.class) {
+ throw e;
+ }
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ clearKeyStore(keyStore);
+
+ // test case sensitive
+ if (isKeyPasswordSupported(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ }
+ if (isReadOnly(keyStore)) {
+ try {
+ keyStore.setKeyEntry(ALIAS_SECRET, getSecretKey(), PASSWORD_KEY, null);
+ fail(keyStore.getType());
+ } catch (UnsupportedOperationException expected) {
+ }
+ continue;
+ }
+ if (isKeyPasswordSupported(keyStore)) {
+ setPrivateKey(keyStore);
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_PRIVATE));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ setPrivateKeyNoPassword(keyStore, ALIAS_NO_PASSWORD_PRIVATE, getPrivateKey());
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_NO_PASSWORD_PRIVATE));
+ }
+ if (isSecretKeyEnabled(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ setSecretKey(keyStore);
+ assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ } else {
+ try {
+ keyStore.setKeyEntry(ALIAS_SECRET, getSecretKey(), PASSWORD_KEY, null);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != KeyStoreException.class
+ && e.getClass() != NullPointerException.class) {
+ throw e;
+ }
+ }
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ populate(keyStore);
+
+ if (isReadOnly(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ assertNull(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
+ } else if (isCaseSensitive(keyStore)) {
+ if (isKeyPasswordSupported(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ setPrivateKey(keyStore, ALIAS_ALT_CASE_PRIVATE, getPrivateKey2());
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ }
+
+ if (isNullPasswordAllowed(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ setPrivateKeyNoPassword(keyStore, ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE,
+ getPrivateKey2());
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ }
+
+ if (isSecretKeyEnabled(keyStore)) {
+ assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
+ setSecretKey(keyStore, ALIAS_ALT_CASE_SECRET, getSecretKey2());
+ assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ assertSecretKey2(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
+ }
+ } else {
+ if (isKeyPasswordSupported(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertPrivateKey(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ setPrivateKey(keyStore, ALIAS_ALT_CASE_PRIVATE, getPrivateKey2());
+ assertPrivateKey2(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ }
+
+ if (isNullPasswordAllowed(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, null));
+ assertPrivateKey(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ setPrivateKey(keyStore, ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, getPrivateKey2());
+ assertPrivateKey2(keyStore.getKey(ALIAS_PRIVATE, null));
+ assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ }
+
+ if (isSecretKeyEnabled(keyStore)) {
+ assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ assertSecretKey(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
+ setSecretKey(keyStore, ALIAS_ALT_CASE_PRIVATE, getSecretKey2());
+ assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ assertSecretKey(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
+ }
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null, null);
+ if (isReadOnly(keyStore)) {
+ try {
+ keyStore.setKeyEntry(ALIAS_PRIVATE,
+ getPrivateKey().getPrivateKey(),
+ null,
+ getPrivateKey().getCertificateChain());
+ fail(keyStore.getType());
+ } catch (UnsupportedOperationException expected) {
+ }
+ continue;
+ }
+
+ // test with null passwords
+ if (isNullPasswordAllowed(keyStore) || isKeyPasswordIgnored(keyStore)) {
+ keyStore.setKeyEntry(ALIAS_PRIVATE,
+ getPrivateKey().getPrivateKey(),
+ null,
+ getPrivateKey().getCertificateChain());
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, null));
+ } else {
+ try {
+ keyStore.setKeyEntry(ALIAS_PRIVATE,
+ getPrivateKey().getPrivateKey(),
+ null,
+ getPrivateKey().getCertificateChain());
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != UnrecoverableKeyException.class
+ && e.getClass() != IllegalArgumentException.class
+ && e.getClass() != KeyStoreException.class) {
+ throw e;
+ }
+ }
+ }
+ if (isSecretKeyEnabled(keyStore)) {
+ if (isNullPasswordAllowed(keyStore) || isKeyPasswordIgnored(keyStore)) {
+ keyStore.setKeyEntry(ALIAS_SECRET, getSecretKey(), null, null);
+ assertSecretKey(keyStore.getKey(ALIAS_SECRET, null));
+ } else {
+ try {
+ keyStore.setKeyEntry(ALIAS_SECRET, getSecretKey(), null, null);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != UnrecoverableKeyException.class
+ && e.getClass() != IllegalArgumentException.class
+ && e.getClass() != KeyStoreException.class) {
+ throw e;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void test_KeyStore_setKeyEntry_array() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ try {
+ keyStore.setKeyEntry(null, null, null);
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null, null);
+
+ if (isReadOnly(keyStore)) {
+ try {
+ keyStore.setKeyEntry(null, null, null);
+ fail(keyStore.getType());
+ } catch (UnsupportedOperationException expected) {
+ }
+ continue;
+ }
+
+ // test odd inputs
+ try {
+ keyStore.setKeyEntry(null, null, null);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != NullPointerException.class
+ && e.getClass() != IllegalArgumentException.class
+ && e.getClass() != KeyStoreException.class
+ && e.getClass() != RuntimeException.class) {
+ throw e;
+ }
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ if (!isNullPasswordAllowed(keyStore)) {
+ // TODO Use EncryptedPrivateKeyInfo to protect keys if
+ // password is required.
+ continue;
+ }
+ if (isSetKeyByteArrayUnimplemented(keyStore)) {
+ continue;
+ }
+
+ clearKeyStore(keyStore);
+
+ // test case sensitive
+ if (isKeyPasswordSupported(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ }
+ if (isReadOnly(keyStore)) {
+ try {
+ setPrivateKeyBytes(keyStore);
+ fail(keyStore.getType());
+ } catch (UnsupportedOperationException expected) {
+ }
+ continue;
+ }
+ if (isKeyPasswordSupported(keyStore)) {
+ setPrivateKeyBytes(keyStore);
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_PRIVATE));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ setPrivateKeyNoPassword(keyStore, ALIAS_NO_PASSWORD_PRIVATE, getPrivateKey());
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_NO_PASSWORD_PRIVATE));
+ }
+ if (isSecretKeyEnabled(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ setSecretKeyBytes(keyStore);
+ assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ } else {
+ try {
+ keyStore.setKeyEntry(ALIAS_SECRET, getSecretKey().getEncoded(), null);
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ if (!isNullPasswordAllowed(keyStore)) {
+ // TODO Use EncryptedPrivateKeyInfo to protect keys if
+ // password is required.
+ continue;
+ }
+ if (isSetKeyByteArrayUnimplemented(keyStore)) {
+ continue;
+ }
+
+ populate(keyStore);
+
+ if (isReadOnly(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ assertNull(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
+ } else if (isCaseSensitive(keyStore)) {
+ if (isKeyPasswordSupported(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ setPrivateKeyBytes(keyStore, ALIAS_ALT_CASE_PRIVATE, getPrivateKey2());
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ setPrivateKeyNoPassword(keyStore, ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE,
+ getPrivateKey2());
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ }
+
+ if (isSecretKeyEnabled(keyStore)) {
+ assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
+ setSecretKeyBytes(keyStore, ALIAS_ALT_CASE_PRIVATE, getSecretKey2());
+ assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ assertSecretKey2(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
+ }
+ } else {
+ if (isKeyPasswordSupported(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertPrivateKey(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ setPrivateKeyBytes(keyStore, ALIAS_ALT_CASE_PRIVATE, getPrivateKey2());
+ assertPrivateKey2(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertPrivateKey(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ setPrivateKeyNoPassword(keyStore, ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE,
+ getPrivateKey2());
+ assertPrivateKey2(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ }
+
+ if (isSecretKeyEnabled(keyStore)) {
+ assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ assertSecretKey(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
+ setSecretKeyBytes(keyStore, ALIAS_ALT_CASE_PRIVATE, getSecretKey2());
+ assertSecretKey2(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ assertSecretKey2(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
+ }
+ }
+ }
+ }
+
+ public void test_KeyStore_setCertificateEntry() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ try {
+ keyStore.setCertificateEntry(null, null);
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ populate(keyStore);
+
+ // test odd inputs
+ try {
+ keyStore.setCertificateEntry(null, null);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != NullPointerException.class
+ && e.getClass() != KeyStoreException.class) {
+ throw e;
+ }
+ }
+
+ if (isReadOnly(keyStore)) {
+ try {
+ assertNull(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ keyStore.setCertificateEntry(ALIAS_CERTIFICATE, null);
+ fail(keyStore.getType());
+ } catch (UnsupportedOperationException expected) {
+ }
+ continue;
+ }
+
+ // Sort of delete by setting null. Note that even though
+ // certificate is null, size doesn't change,
+ // isCertificateEntry returns true, and it is still listed in aliases.
+ if (isCertificateEnabled(keyStore)) {
+ assertCertificate(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ try {
+ int size = keyStore.size();
+ keyStore.setCertificateEntry(ALIAS_CERTIFICATE, null);
+ assertNull(keyStore.getType(), keyStore.getCertificate(ALIAS_CERTIFICATE));
+ assertEquals(keyStore.getType(), size, keyStore.size());
+ assertTrue(keyStore.getType(), keyStore.isCertificateEntry(ALIAS_CERTIFICATE));
+ assertTrue(keyStore.getType(),
+ Collections.list(keyStore.aliases()).contains(ALIAS_CERTIFICATE));
+ } catch (NullPointerException expectedSometimes) {
+ if (!("PKCS12".equalsIgnoreCase(keyStore.getType()) &&
+ "BC".equalsIgnoreCase(keyStore.getProvider().getName()))
+ && !"AndroidKeyStore".equalsIgnoreCase(keyStore.getType())) {
+ throw expectedSometimes;
+ }
+ }
+ } else {
+ try {
+ keyStore.setCertificateEntry(ALIAS_CERTIFICATE, null);
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ if (!isCertificateEnabled(keyStore)) {
+ continue;
+ }
+
+ clearKeyStore(keyStore);
+
+ assertNull(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ if (isReadOnly(keyStore)) {
+ try {
+ setCertificate(keyStore);
+ fail(keyStore.getType());
+ } catch (UnsupportedOperationException expected) {
+ }
+ continue;
+ }
+ setCertificate(keyStore);
+ assertCertificate(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ if (!isCertificateEnabled(keyStore)) {
+ continue;
+ }
+
+ populate(keyStore);
+
+ if (isReadOnly(keyStore)) {
+ assertNull(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ assertNull(keyStore.getCertificate(ALIAS_ALT_CASE_CERTIFICATE));
+ } else if (isCaseSensitive(keyStore)) {
+ assertCertificate(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ assertNull(keyStore.getCertificate(ALIAS_ALT_CASE_CERTIFICATE));
+ setCertificate(keyStore,
+ ALIAS_ALT_CASE_CERTIFICATE,
+ getPrivateKey2().getCertificate());
+ assertCertificate(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ assertCertificate2(keyStore.getCertificate(ALIAS_ALT_CASE_CERTIFICATE));
+ } else {
+ assertCertificate(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ assertCertificate(keyStore.getCertificate(ALIAS_ALT_CASE_CERTIFICATE));
+ setCertificate(keyStore,
+ ALIAS_ALT_CASE_CERTIFICATE,
+ getPrivateKey2().getCertificate());
+ assertCertificate2(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ assertCertificate2(keyStore.getCertificate(ALIAS_ALT_CASE_CERTIFICATE));
+ }
+ }
+ }
+ public void test_KeyStore_deleteEntry() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ try {
+ keyStore.deleteEntry(null);
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null, null);
+
+ if (isReadOnly(keyStore)) {
+ try {
+ keyStore.deleteEntry(null);
+ fail(keyStore.getType());
+ } catch (UnsupportedOperationException expected) {
+ }
+ continue;
+ }
+
+ // test odd inputs
+ try {
+ keyStore.deleteEntry(null);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != NullPointerException.class
+ && e.getClass() != KeyStoreException.class) {
+ throw e;
+ }
+ }
+ keyStore.deleteEntry("");
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ populate(keyStore);
+
+ if (isReadOnly(keyStore)) {
+ try {
+ keyStore.deleteEntry(ALIAS_PRIVATE);
+ } catch (UnsupportedOperationException e) {
+ }
+ continue;
+ }
+
+ // test case sensitive
+ if (isKeyPasswordSupported(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_PRIVATE));
+ keyStore.deleteEntry(ALIAS_PRIVATE);
+ assertNull(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_NO_PASSWORD_PRIVATE));
+ keyStore.deleteEntry(ALIAS_NO_PASSWORD_PRIVATE);
+ assertNull(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ }
+
+ if (isSecretKeyEnabled(keyStore)) {
+ assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ keyStore.deleteEntry(ALIAS_SECRET);
+ assertNull(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ } else {
+ keyStore.deleteEntry(ALIAS_SECRET);
+ }
+
+ if (isCertificateEnabled(keyStore)) {
+ assertCertificate(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ keyStore.deleteEntry(ALIAS_CERTIFICATE);
+ assertNull(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ } else {
+ keyStore.deleteEntry(ALIAS_CERTIFICATE);
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ populate(keyStore);
+
+ // test case insensitive
+
+ if (isCaseSensitive(keyStore)) {
+ if (isKeyPasswordSupported(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ keyStore.deleteEntry(ALIAS_ALT_CASE_PRIVATE);
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ keyStore.deleteEntry(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE);
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ }
+
+ if (isSecretKeyEnabled(keyStore)) {
+ assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ keyStore.deleteEntry(ALIAS_ALT_CASE_SECRET);
+ assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ } else {
+ keyStore.deleteEntry(ALIAS_SECRET);
+ }
+
+ if (isCertificateEnabled(keyStore)) {
+ assertCertificate(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ keyStore.deleteEntry(ALIAS_ALT_CASE_CERTIFICATE);
+ assertCertificate(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ } else {
+ keyStore.deleteEntry(ALIAS_CERTIFICATE);
+ }
+ }
+ }
+ }
+
+ public void test_KeyStore_aliases() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ try {
+ keyStore.aliases();
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null, null);
+ if (isPersistentStorage(keyStore)) {
+ assertNotNull("Should be able to query size: " + keyStore.getType(),
+ keyStore.aliases());
+ } else if (hasDefaultContents(keyStore)) {
+ assertTrue("Should have more than one alias already: " + keyStore.getType(),
+ keyStore.aliases().hasMoreElements());
+ } else {
+ assertEquals("Should have no aliases:" + keyStore.getType(), Collections.EMPTY_SET,
+ new HashSet(Collections.list(keyStore.aliases())));
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ populate(keyStore);
+
+ Set<String> expected = new HashSet<String>();
+ if (isKeyPasswordSupported(keyStore)) {
+ expected.add(ALIAS_PRIVATE);
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ expected.add(ALIAS_NO_PASSWORD_PRIVATE);
+ }
+ if (isSecretKeyEnabled(keyStore)) {
+ expected.add(ALIAS_SECRET);
+ if (isNullPasswordAllowed(keyStore)) {
+ expected.add(ALIAS_NO_PASSWORD_SECRET);
+ }
+ }
+ if (isCertificateEnabled(keyStore)) {
+ expected.add(ALIAS_CERTIFICATE);
+ }
+ if (isPersistentStorage(keyStore)) {
+ assertNotNull("Should be able to query size: " + keyStore.getType(),
+ keyStore.aliases());
+ } else if (hasDefaultContents(keyStore)) {
+ assertTrue(keyStore.aliases().hasMoreElements());
+ } else {
+ assertEquals(expected, new HashSet<String>(Collections.list(keyStore.aliases())));
+ }
+ }
+ }
+
+ public void test_KeyStore_containsAlias() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ try {
+ keyStore.containsAlias(null);
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null, null);
+
+ try {
+ keyStore.containsAlias(null);
+ fail(keyStore.getType());
+ } catch (NullPointerException expected) {
+ }
+
+ assertFalse(keyStore.containsAlias(""));
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ populate(keyStore);
+
+ assertFalse(keyStore.containsAlias(""));
+
+ if (isReadOnly(keyStore)) {
+ assertFalse(keyStore.containsAlias(ALIAS_PRIVATE));
+ continue;
+ }
+ if (isKeyPasswordSupported(keyStore)) {
+ assertTrue(keyStore.containsAlias(ALIAS_PRIVATE));
+ } else if (isNullPasswordAllowed(keyStore)) {
+ assertTrue(keyStore.containsAlias(ALIAS_NO_PASSWORD_PRIVATE));
+ }
+ assertEquals(isSecretKeyEnabled(keyStore), keyStore.containsAlias(ALIAS_SECRET));
+ assertEquals(isCertificateEnabled(keyStore), keyStore.containsAlias(ALIAS_CERTIFICATE));
+
+ assertEquals(!isCaseSensitive(keyStore),
+ keyStore.containsAlias(ALIAS_ALT_CASE_PRIVATE));
+ assertEquals(!isCaseSensitive(keyStore) && isSecretKeyEnabled(keyStore),
+ keyStore.containsAlias(ALIAS_ALT_CASE_SECRET));
+ assertEquals(!isCaseSensitive(keyStore) && isCertificateEnabled(keyStore),
+ keyStore.containsAlias(ALIAS_ALT_CASE_CERTIFICATE));
+ }
+ }
+
+ public void test_KeyStore_size() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ try {
+ keyStore.aliases();
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null, null);
+ if (isPersistentStorage(keyStore)) {
+ assertTrue("Should successfully query size: " + keyStore.getType(),
+ keyStore.size() >= 0);
+ } else if (hasDefaultContents(keyStore)) {
+ assertTrue("Should have non-empty store: " + keyStore.getType(),
+ keyStore.size() > 0);
+ } else {
+ assertEquals("Should have empty store: " + keyStore.getType(), 0, keyStore.size());
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ populate(keyStore);
+ if (hasDefaultContents(keyStore)) {
+ assertTrue("Should have non-empty store: " + keyStore.getType(),
+ keyStore.size() > 0);
+ continue;
+ }
+
+ int expected = 0;
+ if (isKeyPasswordSupported(keyStore)) {
+ expected++;
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ expected++;
+ }
+ if (isSecretKeyEnabled(keyStore)) {
+ expected++;
+ if (isNullPasswordAllowed(keyStore)) {
+ expected++;
+ }
+ }
+ if (isCertificateEnabled(keyStore)) {
+ expected++;
+ }
+ assertEquals(expected, keyStore.size());
+ }
+ }
+
+ public void test_KeyStore_isKeyEntry() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ try {
+ keyStore.isKeyEntry(null);
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null, null);
+
+ try {
+ keyStore.isKeyEntry(null);
+ fail(keyStore.getType());
+ } catch (NullPointerException expected) {
+ }
+
+ assertFalse(keyStore.isKeyEntry(""));
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ populate(keyStore);
+
+ assertFalse(keyStore.isKeyEntry(""));
+ if (isReadOnly(keyStore)) {
+ assertFalse(keyStore.isKeyEntry(ALIAS_PRIVATE));
+ continue;
+ }
+ if (isKeyPasswordSupported(keyStore)) {
+ assertTrue(keyStore.isKeyEntry(ALIAS_PRIVATE));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ assertTrue(keyStore.isKeyEntry(ALIAS_NO_PASSWORD_PRIVATE));
+ }
+ assertEquals(isSecretKeyEnabled(keyStore), keyStore.isKeyEntry(ALIAS_SECRET));
+ assertFalse(keyStore.isKeyEntry(ALIAS_CERTIFICATE));
+
+ assertEquals(!isCaseSensitive(keyStore),
+ keyStore.isKeyEntry(ALIAS_ALT_CASE_PRIVATE));
+ assertEquals(!isCaseSensitive(keyStore) && isSecretKeyEnabled(keyStore),
+ keyStore.isKeyEntry(ALIAS_ALT_CASE_SECRET));
+ assertFalse(keyStore.isKeyEntry(ALIAS_ALT_CASE_CERTIFICATE));
+ }
+ }
+
+ public void test_KeyStore_isCertificateEntry() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ try {
+ keyStore.isCertificateEntry(null);
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null, null);
+
+ if (isCertificateEnabled(keyStore)) {
+ try {
+ keyStore.isCertificateEntry(null);
+ fail(keyStore.getType());
+ } catch (NullPointerException expected) {
+ }
+ } else {
+ assertFalse(keyStore.isCertificateEntry(null));
+ }
+
+ assertFalse(keyStore.isCertificateEntry(""));
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ populate(keyStore);
+
+ assertFalse(keyStore.isCertificateEntry(""));
+
+ if (isKeyPasswordSupported(keyStore)) {
+ assertFalse(keyStore.isCertificateEntry(ALIAS_PRIVATE));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ assertFalse(keyStore.isCertificateEntry(ALIAS_NO_PASSWORD_PRIVATE));
+ }
+ assertFalse(keyStore.isCertificateEntry(ALIAS_SECRET));
+ assertEquals(isCertificateEnabled(keyStore) && !isReadOnly(keyStore),
+ keyStore.isCertificateEntry(ALIAS_CERTIFICATE));
+
+ assertFalse(keyStore.isCertificateEntry(ALIAS_ALT_CASE_PRIVATE));
+ assertFalse(keyStore.isCertificateEntry(ALIAS_ALT_CASE_SECRET));
+ assertEquals(!isCaseSensitive(keyStore)
+ && isCertificateEnabled(keyStore)
+ && !isReadOnly(keyStore),
+ keyStore.isCertificateEntry(ALIAS_ALT_CASE_CERTIFICATE));
+ }
+ }
+
+ public void test_KeyStore_getCertificateAlias() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ try {
+ keyStore.getCertificateAlias(null);
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null, null);
+ assertNull(keyStore.getCertificateAlias(null));
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ populate(keyStore);
+
+ Set<String> expected = new HashSet<String>();
+ if (isKeyPasswordSupported(keyStore)) {
+ expected.add(ALIAS_PRIVATE);
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ expected.add(ALIAS_NO_PASSWORD_PRIVATE);
+ }
+ if (isCertificateEnabled(keyStore)) {
+ expected.add(ALIAS_CERTIFICATE);
+ }
+ String actual = keyStore.getCertificateAlias(getPrivateKey().getCertificate());
+ assertEquals(!isReadOnly(keyStore), expected.contains(actual));
+ assertNull(keyStore.getCertificateAlias(getPrivateKey2().getCertificate()));
+ }
+ }
+
+ public void assertEqualsKeyStores(File expected, char[] storePassword, KeyStore actual)
+ throws Exception{
+ KeyStore ks = KeyStore.getInstance(actual.getType(), actual.getProvider());
+ InputStream is = new FileInputStream(expected);
+ ks.load(is, storePassword);
+ is.close();
+ assertEqualsKeyStores(ks, actual);
+ }
+
+ public void assertEqualsKeyStores(KeyStore expected,
+ ByteArrayOutputStream actual, char[] storePassword)
+ throws Exception{
+ KeyStore ks = KeyStore.getInstance(expected.getType(), expected.getProvider());
+ ks.load(new ByteArrayInputStream(actual.toByteArray()), storePassword);
+ assertEqualsKeyStores(expected, ks);
+ }
+
+ public void assertEqualsKeyStores(KeyStore expected, KeyStore actual)
+ throws Exception{
+ assertEquals(expected.size(), actual.size());
+ for (String alias : Collections.list(actual.aliases())) {
+ if (alias.equals(ALIAS_NO_PASSWORD_PRIVATE)
+ || alias.equals(ALIAS_NO_PASSWORD_SECRET)) {
+ assertEquals(expected.getKey(alias, null),
+ actual.getKey(alias, null));
+ } else {
+ assertEquals(expected.getKey(alias, PASSWORD_KEY),
+ actual.getKey(alias, PASSWORD_KEY));
+ }
+ assertEquals(expected.getCertificate(alias), actual.getCertificate(alias));
+ }
+ }
+
+ public void test_KeyStore_store_OutputStream() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ try {
+ keyStore.store(null, null);
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null, null);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ if (isLoadStoreUnsupported(keyStore) || isReadOnly(keyStore)) {
+ try {
+ keyStore.store(out, null);
+ fail(keyStore.getType());
+ } catch (UnsupportedOperationException expected) {
+ }
+ continue;
+ }
+
+ if (isNullPasswordAllowed(keyStore)) {
+ keyStore.store(out, null);
+ assertEqualsKeyStores(keyStore, out, null);
+ continue;
+ }
+
+ try {
+ keyStore.store(out, null);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != IllegalArgumentException.class
+ && e.getClass() != NullPointerException.class) {
+ throw e;
+ }
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ populate(keyStore);
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ if (isLoadStoreUnsupported(keyStore) || isReadOnly(keyStore)) {
+ try {
+ keyStore.store(out, null);
+ fail(keyStore.getType());
+ } catch (UnsupportedOperationException expected) {
+ }
+ } else if (isNullPasswordAllowed(keyStore)) {
+ keyStore.store(out, null);
+ assertEqualsKeyStores(keyStore, out, null);
+ } else {
+ try {
+ keyStore.store(out, null);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != IllegalArgumentException.class
+ && e.getClass() != NullPointerException.class) {
+ throw e;
+ }
+ }
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null, null);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ if (isLoadStoreUnsupported(keyStore) || isReadOnly(keyStore)) {
+ try {
+ keyStore.store(out, PASSWORD_STORE);
+ fail(keyStore.getType());
+ } catch (UnsupportedOperationException e) {
+ }
+ continue;
+ }
+ keyStore.store(out, PASSWORD_STORE);
+ assertEqualsKeyStores(keyStore, out, PASSWORD_STORE);
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ populate(keyStore);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ if (isLoadStoreUnsupported(keyStore) || isReadOnly(keyStore)) {
+ try {
+ keyStore.store(out, PASSWORD_STORE);
+ fail(keyStore.getType());
+ } catch (UnsupportedOperationException e) {
+ }
+ continue;
+ }
+ keyStore.store(out, PASSWORD_STORE);
+ assertEqualsKeyStores(keyStore, out, PASSWORD_STORE);
+ }
+ }
+
+ public void test_KeyStore_store_LoadStoreParameter() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ try {
+ keyStore.store(null);
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null, null);
+ try {
+ keyStore.store(null);
+ fail(keyStore.getType());
+ } catch (UnsupportedOperationException expected) {
+ assertFalse(isLoadStoreParameterSupported(keyStore));
+ } catch (IllegalArgumentException expected) {
+ // its supported, but null causes an exception
+ assertTrue(isLoadStoreParameterSupported(keyStore));
+ }
+ }
+ }
+
+ public void test_KeyStore_load_InputStream() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null, null);
+ if (isPersistentStorage(keyStore)) {
+ assertTrue("Should be able to query size: " + keyStore.getType(),
+ keyStore.size() >= 0);
+ } else if (hasDefaultContents(keyStore)) {
+ assertTrue("Should have non-empty store: " + keyStore.getType(),
+ keyStore.size() > 0);
+ } else {
+ assertEquals("Should have empty store: " + keyStore.getType(), 0, keyStore.size());
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ if (isLoadStoreUnsupported(keyStore)) {
+ continue;
+ }
+ keyStore.load(null, PASSWORD_STORE);
+ if (isPersistentStorage(keyStore)) {
+ assertTrue("Should be able to query size: " + keyStore.getType(),
+ keyStore.size() >= 0);
+ } else if (hasDefaultContents(keyStore)) {
+ assertTrue("Should have non-empty store: " + keyStore.getType(),
+ keyStore.size() > 0);
+ } else {
+ assertEquals("Should have empty store: " + keyStore.getType(), 0, keyStore.size());
+ }
+ }
+
+ // test_KeyStore_store_OutputStream effectively tests load as well as store
+ }
+
+ public void test_KeyStore_load_LoadStoreParameter() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null);
+ if (isPersistentStorage(keyStore)) {
+ assertTrue("Should be able to query size: " + keyStore.getType(),
+ keyStore.size() >= 0);
+ } else if (hasDefaultContents(keyStore)) {
+ assertTrue("Should have non-empty store: " + keyStore.getType(),
+ keyStore.size() > 0);
+ } else {
+ assertEquals("Should have empty store: " + keyStore.getType(), 0, keyStore.size());
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ try {
+ keyStore.load(new LoadStoreParameter() {
+ public ProtectionParameter getProtectionParameter() {
+ return null;
+ }
+ });
+ fail(keyStore.getType());
+ } catch (UnsupportedOperationException expected) {
+ }
+ }
+ }
+
+ public void test_KeyStore_getEntry() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ try {
+ keyStore.getEntry(null, null);
+ fail(keyStore.getType());
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ populate(keyStore);
+
+ // test odd inputs
+ try {
+ keyStore.getEntry(null, null);
+ fail(keyStore.getType());
+ } catch (NullPointerException expected) {
+ }
+ try {
+ keyStore.getEntry(null, PARAM_KEY);
+ fail(keyStore.getType());
+ } catch (NullPointerException expected) {
+ }
+ assertNull(keyStore.getEntry("", null));
+ assertNull(keyStore.getEntry("", PARAM_KEY));
+
+ // test case sensitive
+ if (isReadOnly(keyStore)) {
+ assertNull(keyStore.getEntry(ALIAS_PRIVATE, PARAM_KEY));
+ } else {
+ if (isKeyPasswordSupported(keyStore)) {
+ assertPrivateKey(keyStore.getEntry(ALIAS_PRIVATE, PARAM_KEY));
+ } else if (isNullPasswordAllowed(keyStore)) {
+ assertPrivateKey(keyStore.getEntry(ALIAS_NO_PASSWORD_PRIVATE, null));
+ }
+ if (isSecretKeyEnabled(keyStore)) {
+ assertSecretKey(keyStore.getEntry(ALIAS_SECRET, PARAM_KEY));
+ } else {
+ assertNull(keyStore.getEntry(ALIAS_SECRET, PARAM_KEY));
+ }
+ if (isCertificateEnabled(keyStore)) {
+ assertCertificate(keyStore.getEntry(ALIAS_CERTIFICATE, null));
+ } else {
+ assertNull(keyStore.getEntry(ALIAS_CERTIFICATE, null));
+ }
+ }
+
+ // test case insensitive
+ if (isCaseSensitive(keyStore) || isReadOnly(keyStore)) {
+ assertNull(keyStore.getEntry(ALIAS_ALT_CASE_PRIVATE, PARAM_KEY));
+ assertNull(keyStore.getEntry(ALIAS_ALT_CASE_SECRET, PARAM_KEY));
+ } else {
+ assertPrivateKey(keyStore.getEntry(ALIAS_ALT_CASE_PRIVATE, PARAM_KEY));
+ if (isSecretKeyEnabled(keyStore)) {
+ assertSecretKey(keyStore.getEntry(ALIAS_ALT_CASE_SECRET, PARAM_KEY));
+ }
+ }
+ if (isCaseSensitive(keyStore) || isReadOnly(keyStore)) {
+ assertNull(keyStore.getEntry(ALIAS_ALT_CASE_CERTIFICATE, null));
+ } else {
+ if (isCertificateEnabled(keyStore)) {
+ assertCertificate(keyStore.getEntry(ALIAS_ALT_CASE_CERTIFICATE, null));
+ }
+ }
+
+ // test with null passwords
+ if (isReadOnly(keyStore)) {
+ assertNull(keyStore.getEntry(ALIAS_NO_PASSWORD_PRIVATE, null));
+ } else if (isNullPasswordAllowed(keyStore)) {
+ assertPrivateKey(keyStore.getEntry(ALIAS_NO_PASSWORD_PRIVATE, null));
+ } else if (isKeyPasswordSupported(keyStore) && isKeyPasswordIgnored(keyStore)) {
+ assertPrivateKey(keyStore.getEntry(ALIAS_PRIVATE, null));
+ } else if (isKeyPasswordIgnored(keyStore)) {
+ try {
+ keyStore.getEntry(ALIAS_PRIVATE, null);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != UnrecoverableKeyException.class
+ && e.getClass() != IllegalArgumentException.class) {
+ throw e;
+ }
+ }
+ }
+ if (isReadOnly(keyStore)) {
+ assertNull(keyStore.getEntry(ALIAS_SECRET, null));
+ } else if (isSecretKeyEnabled(keyStore)) {
+ try {
+ keyStore.getEntry(ALIAS_SECRET, null);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != UnrecoverableKeyException.class
+ && e.getClass() != IllegalArgumentException.class) {
+ throw e;
+ }
+ }
+ }
+
+ // test with bad passwords
+ if (isReadOnly(keyStore)) {
+ assertNull(keyStore.getEntry(ALIAS_PRIVATE, PARAM_BAD));
+ } else if (isKeyPasswordSupported(keyStore) && isKeyPasswordIgnored(keyStore)) {
+ assertPrivateKey(keyStore.getEntry(ALIAS_PRIVATE, PARAM_BAD));
+ } else if (isKeyPasswordSupported(keyStore)) {
+ try {
+ keyStore.getEntry(ALIAS_PRIVATE, PARAM_BAD);
+ fail(keyStore.getType());
+ } catch (UnrecoverableKeyException expected) {
+ }
+ }
+ if (isReadOnly(keyStore)) {
+ assertNull(keyStore.getEntry(ALIAS_SECRET, PARAM_BAD));
+ } else if (isSecretKeyEnabled(keyStore)) {
+ try {
+ keyStore.getEntry(ALIAS_SECRET, PARAM_BAD);
+ fail(keyStore.getType());
+ } catch (UnrecoverableKeyException expected) {
+ }
+ }
+ }
+ }
+
+ public static class FakeProtectionParameter implements ProtectionParameter {
+ }
+
+ public void test_KeyStore_setEntry() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null, null);
+ try {
+ keyStore.setEntry(null, null, null);
+ fail(keyStore.getType());
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null, null);
+
+ try {
+ keyStore.setEntry(ALIAS_PRIVATE, getPrivateKey(), new FakeProtectionParameter());
+ fail("Should not accept unknown ProtectionParameter: " + keyStore.getProvider());
+ } catch (KeyStoreException expected) {
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null, null);
+
+ // test odd inputs
+ try {
+ keyStore.setEntry(null, null, null);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != NullPointerException.class
+ && e.getClass() != KeyStoreException.class) {
+ throw e;
+ }
+ }
+ try {
+ keyStore.setEntry(null, null, PARAM_KEY);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != NullPointerException.class
+ && e.getClass() != KeyStoreException.class) {
+ throw e;
+ }
+ }
+ try {
+ keyStore.setEntry("", null, PARAM_KEY);
+ fail(keyStore.getType());
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ clearKeyStore(keyStore);
+
+ // test case sensitive
+ assertNull(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ if (isReadOnly(keyStore)) {
+ try {
+ keyStore.setEntry(ALIAS_PRIVATE, getPrivateKey(), PARAM_KEY);
+ fail(keyStore.getType());
+ } catch (UnsupportedOperationException expected) {
+ }
+ continue;
+ }
+ if (isKeyPasswordSupported(keyStore)) {
+ keyStore.setEntry(ALIAS_PRIVATE, getPrivateKey(), PARAM_KEY);
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_PRIVATE));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ keyStore.setEntry(ALIAS_NO_PASSWORD_PRIVATE, getPrivateKey(), null);
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_NO_PASSWORD_PRIVATE));
+ }
+ if (isSecretKeyEnabled(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ keyStore.setEntry(ALIAS_SECRET, new SecretKeyEntry(getSecretKey()), PARAM_KEY);
+ assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ } else {
+ try {
+ keyStore.setKeyEntry(ALIAS_SECRET, getSecretKey(), PASSWORD_KEY, null);
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+ if (isCertificateEnabled(keyStore)) {
+ assertNull(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ keyStore.setEntry(ALIAS_CERTIFICATE,
+ new TrustedCertificateEntry(getPrivateKey().getCertificate()),
+ null);
+ assertCertificate(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ } else {
+ try {
+ keyStore.setEntry(ALIAS_CERTIFICATE,
+ new TrustedCertificateEntry(getPrivateKey().getCertificate()),
+ null);
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+ if (isKeyPasswordSupported(keyStore)) {
+ keyStore.setEntry(ALIAS_UNICODE_PRIVATE, getPrivateKey(), PARAM_KEY);
+ assertPrivateKey(keyStore.getKey(ALIAS_UNICODE_PRIVATE, PASSWORD_KEY));
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_UNICODE_PRIVATE));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ keyStore.setEntry(ALIAS_UNICODE_NO_PASSWORD_PRIVATE, getPrivateKey(), null);
+ assertPrivateKey(keyStore.getKey(ALIAS_UNICODE_NO_PASSWORD_PRIVATE, null));
+ assertCertificateChain(keyStore
+ .getCertificateChain(ALIAS_UNICODE_NO_PASSWORD_PRIVATE));
+ }
+ if (isSecretKeyEnabled(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_UNICODE_SECRET, PASSWORD_KEY));
+ keyStore.setEntry(ALIAS_UNICODE_SECRET, new SecretKeyEntry(getSecretKey()), PARAM_KEY);
+ assertSecretKey(keyStore.getKey(ALIAS_UNICODE_SECRET, PASSWORD_KEY));
+ } else {
+ try {
+ keyStore.setKeyEntry(ALIAS_UNICODE_SECRET, getSecretKey(), PASSWORD_KEY, null);
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ populate(keyStore);
+
+ if (isReadOnly(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ assertNull(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
+ } else if (isCaseSensitive(keyStore)) {
+ if (isKeyPasswordSupported(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ keyStore.setEntry(ALIAS_ALT_CASE_PRIVATE, getPrivateKey2(), PARAM_KEY);
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ }
+
+ if (isNullPasswordAllowed(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ keyStore.setEntry(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, getPrivateKey2(), null);
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ }
+
+ if (isSecretKeyEnabled(keyStore)) {
+ assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
+ keyStore.setEntry(ALIAS_ALT_CASE_SECRET,
+ new SecretKeyEntry(getSecretKey2()),
+ PARAM_KEY);
+ assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ assertSecretKey2(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
+ }
+
+ if (isCertificateEnabled(keyStore)) {
+ assertCertificate(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ assertNull(keyStore.getCertificate(ALIAS_ALT_CASE_CERTIFICATE));
+ keyStore.setEntry(ALIAS_ALT_CASE_CERTIFICATE,
+ new TrustedCertificateEntry(
+ getPrivateKey2().getCertificate()),
+ null);
+ assertCertificate(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ assertCertificate2(keyStore.getCertificate(ALIAS_ALT_CASE_CERTIFICATE));
+ keyStore.setEntry(ALIAS_UNICODE_CERTIFICATE,
+ new TrustedCertificateEntry(
+ getPrivateKey().getCertificate()),
+ null);
+ assertCertificate(keyStore.getCertificate(ALIAS_UNICODE_CERTIFICATE));
+ }
+ } else {
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertPrivateKey(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ keyStore.setEntry(ALIAS_ALT_CASE_PRIVATE, getPrivateKey2(), PARAM_KEY);
+ assertPrivateKey2(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+
+ if (isSecretKeyEnabled(keyStore)) {
+ assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ assertSecretKey(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
+ keyStore.setEntry(ALIAS_ALT_CASE_SECRET,
+ new SecretKeyEntry(getSecretKey2()),
+ PARAM_KEY);
+ assertSecretKey2(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
+ assertSecretKey2(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
+ }
+
+ if (isCertificateEnabled(keyStore)) {
+ assertCertificate(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ assertCertificate(keyStore.getCertificate(ALIAS_ALT_CASE_CERTIFICATE));
+ keyStore.setEntry(ALIAS_ALT_CASE_CERTIFICATE,
+ new TrustedCertificateEntry(
+ getPrivateKey2().getCertificate()),
+ null);
+ assertCertificate2(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ assertCertificate2(keyStore.getCertificate(ALIAS_ALT_CASE_CERTIFICATE));
+ keyStore.setEntry(ALIAS_UNICODE_CERTIFICATE,
+ new TrustedCertificateEntry(
+ getPrivateKey().getCertificate()),
+ null);
+ assertCertificate(keyStore.getCertificate(ALIAS_UNICODE_CERTIFICATE));
+ }
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null, null);
+
+ // test with null/non-null passwords
+ if (isReadOnly(keyStore)) {
+ try {
+ keyStore.setEntry(ALIAS_PRIVATE, getPrivateKey(), null);
+ fail(keyStore.getType());
+ } catch (UnsupportedOperationException expected) {
+ }
+ try {
+ keyStore.setEntry(ALIAS_SECRET, new SecretKeyEntry(getSecretKey()), null);
+ fail(keyStore.getType());
+ } catch (UnsupportedOperationException expected) {
+ }
+ try {
+ keyStore.setEntry(ALIAS_CERTIFICATE,
+ new TrustedCertificateEntry(getPrivateKey().getCertificate()),
+ null);
+ fail(keyStore.getType());
+ } catch (UnsupportedOperationException expected) {
+ }
+ continue;
+ }
+ if (isNullPasswordAllowed(keyStore) || isKeyPasswordIgnored(keyStore)) {
+ for (String keyType : KEY_TYPES) {
+ keyStore.setEntry(ALIAS_PRIVATE, getPrivateKey(keyType), null);
+ assertPrivateKey(keyType, keyStore.getKey(ALIAS_PRIVATE, null));
+ }
+ } else {
+ try {
+ keyStore.setEntry(ALIAS_PRIVATE, getPrivateKey(), null);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != UnrecoverableKeyException.class
+ && e.getClass() != IllegalArgumentException.class
+ && e.getClass() != KeyStoreException.class) {
+ throw e;
+ }
+ }
+ }
+ if (isSecretKeyEnabled(keyStore)) {
+ if (isNullPasswordAllowed(keyStore) || isKeyPasswordIgnored(keyStore)) {
+ keyStore.setEntry(ALIAS_SECRET, new SecretKeyEntry(getSecretKey()), null);
+ assertSecretKey(keyStore.getKey(ALIAS_SECRET, null));
+ } else {
+ try {
+ keyStore.setEntry(ALIAS_SECRET, new SecretKeyEntry(getSecretKey()), null);
+ fail(keyStore.getType());
+ } catch (Exception e) {
+ if (e.getClass() != UnrecoverableKeyException.class
+ && e.getClass() != IllegalArgumentException.class
+ && e.getClass() != KeyStoreException.class) {
+ throw e;
+ }
+ }
+ }
+ }
+ if (isCertificateEnabled(keyStore)) {
+ if (isNullPasswordAllowed(keyStore) || isKeyPasswordIgnored(keyStore)) {
+ keyStore.setEntry(ALIAS_CERTIFICATE,
+ new TrustedCertificateEntry(getPrivateKey().getCertificate()),
+ PARAM_KEY);
+ assertCertificate(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ } else {
+ try {
+ keyStore.setEntry(ALIAS_CERTIFICATE,
+ new TrustedCertificateEntry(
+ getPrivateKey().getCertificate()),
+ PARAM_KEY);
+ fail(keyStore.getType());
+ } catch (KeyStoreException expected) {
+ }
+ }
+ }
+ }
+ }
+
+ public void test_KeyStore_entryInstanceOf() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ try {
+ keyStore.entryInstanceOf(null, null);
+ fail(keyStore.getType());
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null, null);
+
+ try {
+ keyStore.entryInstanceOf(null, null);
+ fail(keyStore.getType());
+ } catch (NullPointerException expected) {
+ }
+ try {
+ keyStore.entryInstanceOf(null, Entry.class);
+ fail(keyStore.getType());
+ } catch (NullPointerException expected) {
+ }
+ try {
+ keyStore.entryInstanceOf("", null);
+ fail(keyStore.getType());
+ } catch (NullPointerException expected) {
+ }
+
+ assertFalse(keyStore.entryInstanceOf("", Entry.class));
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ populate(keyStore);
+
+ // test odd inputs
+ assertFalse(keyStore.entryInstanceOf("", Entry.class));
+ assertFalse(keyStore.entryInstanceOf("", PrivateKeyEntry.class));
+ assertFalse(keyStore.entryInstanceOf("", SecretKeyEntry.class));
+ assertFalse(keyStore.entryInstanceOf("", TrustedCertificateEntry.class));
+
+ if (isReadOnly(keyStore)) {
+ assertFalse(keyStore.entryInstanceOf(ALIAS_PRIVATE, PrivateKeyEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_PRIVATE, SecretKeyEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_PRIVATE, TrustedCertificateEntry.class));
+
+ assertFalse(keyStore.entryInstanceOf(ALIAS_SECRET, SecretKeyEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_SECRET, PrivateKeyEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_SECRET, TrustedCertificateEntry.class));
+
+ assertFalse(keyStore.entryInstanceOf(ALIAS_CERTIFICATE,
+ TrustedCertificateEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_CERTIFICATE, PrivateKeyEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_CERTIFICATE, SecretKeyEntry.class));
+ continue;
+ }
+
+ // test case sensitive
+ assertEquals(isKeyPasswordSupported(keyStore),
+ keyStore.entryInstanceOf(ALIAS_PRIVATE, PrivateKeyEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_PRIVATE, SecretKeyEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_PRIVATE, TrustedCertificateEntry.class));
+
+ assertEquals(isNullPasswordAllowed(keyStore),
+ keyStore.entryInstanceOf(ALIAS_NO_PASSWORD_PRIVATE, PrivateKeyEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_NO_PASSWORD_PRIVATE, SecretKeyEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_NO_PASSWORD_PRIVATE,
+ TrustedCertificateEntry.class));
+
+ assertEquals(isSecretKeyEnabled(keyStore),
+ keyStore.entryInstanceOf(ALIAS_SECRET, SecretKeyEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_SECRET, PrivateKeyEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_SECRET, TrustedCertificateEntry.class));
+
+ assertEquals(isCertificateEnabled(keyStore),
+ keyStore.entryInstanceOf(ALIAS_CERTIFICATE,
+ TrustedCertificateEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_CERTIFICATE, PrivateKeyEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_CERTIFICATE, SecretKeyEntry.class));
+
+ // test case insensitive
+ assertEquals(!isCaseSensitive(keyStore),
+ keyStore.entryInstanceOf(ALIAS_ALT_CASE_PRIVATE, PrivateKeyEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_ALT_CASE_PRIVATE, SecretKeyEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_ALT_CASE_PRIVATE,
+ TrustedCertificateEntry.class));
+
+ assertEquals(!isCaseSensitive(keyStore) && isSecretKeyEnabled(keyStore),
+ keyStore.entryInstanceOf(ALIAS_ALT_CASE_SECRET, SecretKeyEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_ALT_CASE_SECRET, PrivateKeyEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_ALT_CASE_SECRET,
+ TrustedCertificateEntry.class));
+
+ assertEquals(!isCaseSensitive(keyStore) && isCertificateEnabled(keyStore),
+ keyStore.entryInstanceOf(ALIAS_ALT_CASE_CERTIFICATE,
+ TrustedCertificateEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_ALT_CASE_CERTIFICATE,
+ PrivateKeyEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_ALT_CASE_CERTIFICATE, SecretKeyEntry.class));
+ }
+ }
+
+ // TODO(27810271): investigate why this is taking too long for armeabi-v7a
+ @TimeoutReq(minutes=10)
+ public void test_KeyStore_Builder() throws Exception {
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null, null);
+ try {
+ Builder.newInstance(keyStore, null);
+ fail(keyStore.getType());
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ try {
+ Builder.newInstance(keyStore.getType(),
+ keyStore.getProvider(),
+ null);
+ fail(keyStore.getType());
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ try {
+ Builder.newInstance(null,
+ null,
+ null,
+ null);
+ fail(keyStore.getType());
+ } catch (NullPointerException expected) {
+ }
+ try {
+ Builder.newInstance(keyStore.getType(),
+ keyStore.getProvider(),
+ null,
+ null);
+ fail(keyStore.getType());
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ keyStore.load(null, null);
+ Builder builder = Builder.newInstance(keyStore, PARAM_STORE);
+ try {
+ builder.getProtectionParameter(null);
+ fail(keyStore.getType());
+ } catch (NullPointerException expected) {
+ }
+ assertEquals(keyStore, builder.getKeyStore());
+ try {
+ builder.getProtectionParameter(null);
+ fail(keyStore.getType());
+ } catch (NullPointerException expected) {
+ }
+ assertEquals(PARAM_STORE, builder.getProtectionParameter(""));
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ populate(keyStore);
+
+ File file = File.createTempFile("keystore", keyStore.getProvider().getName());
+ OutputStream os = null;
+ try {
+ os = new FileOutputStream(file);
+ if (isLoadStoreUnsupported(keyStore) || isReadOnly(keyStore)) {
+ try {
+ keyStore.store(os, PASSWORD_STORE);
+ fail(keyStore.getType());
+ } catch (UnsupportedOperationException expected) {
+ }
+ continue;
+ }
+
+ keyStore.store(os, PASSWORD_STORE);
+ os.close();
+ Builder builder = Builder.newInstance(keyStore.getType(),
+ keyStore.getProvider(),
+ file,
+ PARAM_STORE);
+ assertEquals(keyStore.getType(), builder.getKeyStore().getType());
+ assertEquals(keyStore.getProvider(), builder.getKeyStore().getProvider());
+ assertEquals(PARAM_STORE, builder.getProtectionParameter(""));
+ assertEqualsKeyStores(file, PASSWORD_STORE, keyStore);
+ } finally {
+ try {
+ if (os != null) {
+ os.close();
+ }
+ } catch (IOException ignored) {
+ }
+ file.delete();
+ }
+ }
+
+ for (KeyStore keyStore : keyStores()) {
+ if (isLoadStoreUnsupported(keyStore)) {
+ continue;
+ }
+ Builder builder = Builder.newInstance(keyStore.getType(),
+ keyStore.getProvider(),
+ PARAM_STORE);
+ assertEquals(keyStore.getType(), builder.getKeyStore().getType());
+ assertEquals(keyStore.getProvider(), builder.getKeyStore().getProvider());
+ assertEquals(PARAM_STORE, builder.getProtectionParameter(""));
+ }
+ }
+
+ public void test_KeyStore_cacerts() throws Exception {
+ if (StandardNames.IS_RI) {
+ return;
+ }
+ KeyStore ks = KeyStore.getInstance("AndroidCAStore");
+ assertEquals("AndroidCAStore", ks.getType());
+ assertEquals("HarmonyJSSE", ks.getProvider().getName());
+
+ ks.load(null, null);
+ for (String alias : Collections.list(ks.aliases())) {
+ Certificate c = null;
+ try {
+ c = ks.getCertificate(alias);
+ assertNotNull(c);
+ assertTrue(ks.isCertificateEntry(alias));
+ assertTrue(ks.entryInstanceOf(alias, TrustedCertificateEntry.class));
+ assertEquals(alias, ks.getCertificateAlias(c));
+
+ assertTrue(c instanceof X509Certificate);
+ X509Certificate cert = (X509Certificate) c;
+ assertEquals(cert.getSubjectUniqueID(), cert.getIssuerUniqueID());
+ assertNotNull(cert.getPublicKey());
+
+ assertTrue(ks.containsAlias(alias));
+ assertNotNull(ks.getCreationDate(alias));
+ assertNotNull(ks.getEntry(alias, null));
+
+ assertFalse(ks.isKeyEntry(alias));
+ assertNull(ks.getKey(alias, null));
+ assertNull(ks.getCertificateChain(alias));
+
+ } catch (Throwable t) {
+ throw new Exception("alias=" + alias + " cert=" + c, t);
+ }
+ }
+ }
+
+ // http://b/857840: want JKS key store
+ public void testDefaultKeystore() {
+ String type = KeyStore.getDefaultType();
+ assertEquals(StandardNames.KEY_STORE_ALGORITHM, type);
+
+ try {
+ KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());
+ assertNotNull("Keystore must not be null", store);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+
+ try {
+ KeyStore store = KeyStore.getInstance(StandardNames.KEY_STORE_ALGORITHM);
+ assertNotNull("Keystore must not be null", store);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+}
diff --git a/tests/tests/location/src/android/location/cts/GnssMeasurementWhenNoLocationTest.java b/tests/tests/location/src/android/location/cts/GnssMeasurementWhenNoLocationTest.java
index c0c10d6..7a2bead 100644
--- a/tests/tests/location/src/android/location/cts/GnssMeasurementWhenNoLocationTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssMeasurementWhenNoLocationTest.java
@@ -121,13 +121,18 @@
return;
}
if (!mGpsStatusListener.isGpsStatusReceived()) {
- Log.i(TAG, "No Satellites are visible. Device may be Indoor. Skip test.");
+ Log.i(TAG, "No Satellites are visible. Device may be indoors. Skip test.");
return;
}
List<GnssMeasurementsEvent> events = mMeasurementListener.getEvents();
Log.i(TAG, "Number of GPS measurement events received = " + events.size());
+ if (events.isEmpty()) {
+ Log.i(TAG, "No GPS measurement events received. Device may be indoors. Skip test.");
+ return;
+ }
+
// If device is not indoor, verify that we receive GPS measurements before being able to
// calculate the position solution and verify that mandatory fields of GnssMeasurement are
// in expected ranges.
diff --git a/tests/tests/media/res/raw/voice12_48k_128kbps_15s_ac3.raw b/tests/tests/media/res/raw/voice12_48k_128kbps_15s_ac3.raw
new file mode 100644
index 0000000..e8b46af
--- /dev/null
+++ b/tests/tests/media/res/raw/voice12_48k_128kbps_15s_ac3.raw
Binary files differ
diff --git a/tests/tests/media/res/raw/voice12_48k_128kbps_15s_ac3_readme.txt b/tests/tests/media/res/raw/voice12_48k_128kbps_15s_ac3_readme.txt
new file mode 100644
index 0000000..3073d48
--- /dev/null
+++ b/tests/tests/media/res/raw/voice12_48k_128kbps_15s_ac3_readme.txt
@@ -0,0 +1,7 @@
+file=voice12_48k_128kbps_15s.raw
+author=Phil Burk
+copyright=2016 Google Inc
+license=Apache Open Source V2
+channels=2
+encoding=AC3
+rate=48000
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackSurroundTest.java b/tests/tests/media/src/android/media/cts/AudioTrackSurroundTest.java
new file mode 100644
index 0000000..2ab030a
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/AudioTrackSurroundTest.java
@@ -0,0 +1,537 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import android.annotation.RawRes;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.Resources;
+import android.cts.util.CtsAndroidTestCase;
+import android.media.AudioAttributes;
+import android.media.AudioDeviceInfo;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioTimestamp;
+import android.media.AudioTrack;
+import android.util.Log;
+
+import java.io.BufferedInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Random;
+
+// Test the Java AudioTrack surround sound and HDMI passthrough.
+// Most tests involve creating a track with a given format and then playing
+// a few seconds of audio. The playback is verified by measuring the output
+// sample rate based on the AudioTimestamps.
+
+public class AudioTrackSurroundTest extends CtsAndroidTestCase {
+ private static final String TAG = "AudioTrackSurroundTest";
+
+ private static final double MAX_RATE_TOLERANCE_HZ = 100.0;
+ private static final double MAX_INSTANTANEOUS_RATE_TOLERANCE_HZ = 5000.0;
+ private static final boolean LOG_TIMESTAMPS = false; // set true for debugging
+
+ // Set this true to prefer the device that supports the particular encoding.
+ // But note that as of 3/25/2016, a bug causes Direct tracks to fail.
+ // So only set true when debugging that problem.
+ private static final boolean USE_PREFERRED_DEVICE = false;
+
+ private final static long NANOS_PER_MILLISECOND = 1000000L;
+ private final static int MILLIS_PER_SECOND = 1000;
+ private final static long NANOS_PER_SECOND = NANOS_PER_MILLISECOND * MILLIS_PER_SECOND;
+
+ private final static int RES_AC3_VOICE_48000 = R.raw.voice12_48k_128kbps_15s_ac3;
+
+ // Devices that support various encodings.
+ private static boolean mDeviceScanComplete = false;
+ private static AudioDeviceInfo mInfoPCM16 = null;
+ private static AudioDeviceInfo mInfoAC3 = null;
+ private static AudioDeviceInfo mInfoE_AC3 = null;
+ private static AudioDeviceInfo mInfoDTS = null;
+ private static AudioDeviceInfo mInfoDTS_HD = null;
+ private static AudioDeviceInfo mInfoIEC61937 = null;
+
+ private static void log(String testName, String message) {
+ Log.i(TAG, "[" + testName + "] " + message);
+ }
+
+ private static void logw(String testName, String message) {
+ Log.w(TAG, "[" + testName + "] " + message);
+ }
+
+ private static void loge(String testName, String message) {
+ Log.e(TAG, "[" + testName + "] " + message);
+ }
+
+ // This is a special method that is called automatically before each test.
+ @Override
+ protected void setUp() throws Exception {
+ // Note that I tried to only scan for encodings once but the static
+ // data did not persist properly. That may be a bug.
+ // For now, just scan before every test.
+ scanDevicesForEncodings();
+ }
+
+ private void scanDevicesForEncodings() throws Exception {
+ // Scan devices to see which encodings are supported.
+ AudioManager audioManager = (AudioManager) getContext()
+ .getSystemService(Context.AUDIO_SERVICE);
+ AudioDeviceInfo[] infos = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
+ for (AudioDeviceInfo info : infos) {
+ log("scanDevicesForEncodings", "scanning devices, info = " + info
+ + ", id = " + info.getId() + "---------------");
+ if (info.isSink()) {
+ for (int encoding : info.getEncodings()) {
+ switch (encoding) {
+ case AudioFormat.ENCODING_PCM_16BIT:
+ mInfoPCM16 = info;
+ log(TAG, "mInfoPCM16 set to " + info);
+ break;
+ case AudioFormat.ENCODING_AC3:
+ mInfoAC3 = info;
+ log(TAG, "mInfoAC3 set to " + info);
+ break;
+ case AudioFormat.ENCODING_E_AC3:
+ mInfoE_AC3 = info;
+ log(TAG, "mInfoE_AC3 set to " + info);
+ break;
+ case AudioFormat.ENCODING_DTS:
+ mInfoDTS = info;
+ log(TAG, "mInfoDTS set to " + info);
+ break;
+ case AudioFormat.ENCODING_DTS_HD:
+ mInfoDTS_HD = info;
+ log(TAG, "mInfoDTS_HD set to " + info);
+ break;
+ case AudioFormat.ENCODING_IEC61937:
+ mInfoIEC61937 = info;
+ log(TAG, "mInfoIEC61937 set to " + info);
+ break;
+ default:
+ // This is OK. It is just an encoding that we don't care about.
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Load a resource into a byte[]
+ private byte[] loadRawResourceBytes(@RawRes int id) throws Exception {
+ AssetFileDescriptor masterFd = getContext().getResources().openRawResourceFd(id);
+ long masterLength = masterFd.getLength();
+ byte[] masterBuffer = new byte[(int) masterLength];
+ InputStream is = masterFd.createInputStream();
+ BufferedInputStream bis = new BufferedInputStream(is);
+ int result = bis.read(masterBuffer);
+ bis.close();
+ masterFd.close();
+ return masterBuffer;
+ }
+
+ // Load a resource into a short[]
+ private short[] loadRawResourceShorts(@RawRes int id) throws Exception {
+ AssetFileDescriptor masterFd = getContext().getResources().openRawResourceFd(id);
+ long masterLength = masterFd.getLength();
+ short[] masterBuffer = new short[(int) (masterLength / 2)];
+ InputStream is = masterFd.createInputStream();
+ BufferedInputStream bis = new BufferedInputStream(is);
+ for (int i = 0; i < masterBuffer.length; i++) {
+ int lo = bis.read(); // assume Little Endian
+ int hi = bis.read();
+ masterBuffer[i] = (short) (hi * 256 + lo);
+ }
+ bis.close();
+ masterFd.close();
+ return masterBuffer;
+ }
+
+ public void testLoadSineSweep() throws Exception {
+ final String TEST_NAME = "testLoadSineSweep";
+ short[] shortData = loadRawResourceShorts(R.raw.sinesweepraw);
+ assertTrue(TEST_NAME + ": load sinesweepraw as shorts", shortData.length > 100);
+ byte[] byteData = loadRawResourceBytes(R.raw.sinesweepraw);
+ assertTrue(TEST_NAME + ": load sinesweepraw as bytes", byteData.length > shortData.length);
+ }
+
+ private static AudioTrack createAudioTrack(int sampleRate, int encoding, int channelConfig) {
+ final String TEST_NAME = "createAudioTrack";
+ int minBufferSize = AudioTrack.getMinBufferSize(
+ sampleRate, channelConfig,
+ encoding);
+ assertTrue(TEST_NAME + ": getMinBufferSize", minBufferSize > 0);
+ int bufferSize = minBufferSize * 3; // plenty big
+ AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC,
+ sampleRate, channelConfig,
+ encoding, bufferSize,
+ AudioTrack.MODE_STREAM);
+ return track;
+ }
+
+ static class TimestampAnalyzer {
+ ArrayList<AudioTimestamp> mTimestamps = new ArrayList<AudioTimestamp>();
+ AudioTimestamp mPreviousTimestamp = null;
+
+ static String timestampToString(AudioTimestamp timestamp) {
+ if (timestamp == null)
+ return "null";
+ return "(pos = " + timestamp.framePosition + ", nanos = " + timestamp.nanoTime + ")";
+ }
+
+ // Add timestamp if unique and valid.
+ void addTimestamp(AudioTrack track) {
+ AudioTimestamp timestamp = new AudioTimestamp();
+ boolean gotTimestamp = track.getTimestamp(timestamp);
+ if (gotTimestamp) {
+ // Only save timestamps after the data is flowing.
+ if (mPreviousTimestamp != null) {
+ if ((timestamp.framePosition > 0)
+ && (timestamp.nanoTime != mPreviousTimestamp.nanoTime)) {
+ mTimestamps.add(timestamp);
+ }
+ }
+ mPreviousTimestamp = timestamp;
+ }
+ }
+
+ // Use collected timestamps to estimate a sample rate.
+ double estimateSampleRate() {
+ assertTrue("expect many timestamps, got " + mTimestamps.size(),
+ mTimestamps.size() > 10);
+ // Use first and last timestamp to get the most accurate rate.
+ AudioTimestamp first = mTimestamps.get(0);
+ AudioTimestamp last = mTimestamps.get(mTimestamps.size() - 1);
+ double measuredRate = calculateSampleRate(first, last);
+
+ AudioTimestamp previous = null;
+ // Make sure the timestamps are smooth and don't go retrograde.
+ for (AudioTimestamp timestamp : mTimestamps) {
+ if (previous != null) {
+ double instantaneousRate = calculateSampleRate(previous, timestamp);
+ assertEquals("instantaneous sample rate should match long term rate",
+ measuredRate, instantaneousRate, MAX_INSTANTANEOUS_RATE_TOLERANCE_HZ);
+ assertTrue("framePosition should be monotonic",
+ timestamp.framePosition > previous.framePosition);
+ assertTrue("nanoTime should be monotonic",
+ timestamp.nanoTime > previous.nanoTime);
+ }
+ previous = timestamp;
+ }
+ return measuredRate;
+ }
+
+ /**
+ * @param timestamp1
+ * @param timestamp2
+ */
+ private double calculateSampleRate(AudioTimestamp timestamp1, AudioTimestamp timestamp2) {
+ long elapsedFrames = timestamp2.framePosition - timestamp1.framePosition;
+ long elapsedNanos = timestamp2.nanoTime - timestamp1.nanoTime;
+ double measuredRate = elapsedFrames * (double) NANOS_PER_SECOND / elapsedNanos;
+ if (LOG_TIMESTAMPS) {
+ Log.i(TAG, "calculateSampleRate(), elapsedFrames =, " + elapsedFrames
+ + ", measuredRate =, "
+ + (int) measuredRate);
+ }
+ return measuredRate;
+ }
+ }
+
+ // Class for looping a recording for several seconds and measuring the sample rate.
+ // This is not static because it needs to call getContext().
+ abstract class SamplePlayerBase {
+ private final int mSampleRate;
+ private final int mEncoding;
+ private final int mChannelConfig;
+ private int mBlockSize = 512;
+ protected int mOffset = 0;
+ protected AudioTrack mTrack;
+ private final TimestampAnalyzer mTimestampAnalyzer = new TimestampAnalyzer();
+
+ SamplePlayerBase(int sampleRate, int encoding, int channelConfig) {
+ mSampleRate = sampleRate;
+ mEncoding = encoding;
+ mChannelConfig = channelConfig;
+ }
+
+ // Use abstract write to handle byte[] or short[] data.
+ protected abstract int writeBlock(int numSamples);
+
+ private int primeBuffer() {
+ // Will not block when track is stopped.
+ return writeBlock(Integer.MAX_VALUE);
+ }
+
+ /**
+ * Use a device that we know supports the current encoding.
+ */
+ private void usePreferredDevice() {
+ AudioDeviceInfo info = null;
+ switch (mEncoding) {
+ case AudioFormat.ENCODING_PCM_16BIT:
+ info = mInfoPCM16;
+ break;
+ case AudioFormat.ENCODING_AC3:
+ info = mInfoAC3;
+ break;
+ case AudioFormat.ENCODING_E_AC3:
+ info = mInfoE_AC3;
+ break;
+ case AudioFormat.ENCODING_DTS:
+ info = mInfoDTS;
+ break;
+ case AudioFormat.ENCODING_DTS_HD:
+ info = mInfoDTS_HD;
+ break;
+ case AudioFormat.ENCODING_IEC61937:
+ info = mInfoIEC61937;
+ break;
+ default:
+ break;
+ }
+
+ if (info != null) {
+ log(TAG, "track.setPreferredDevice(" + info + ")");
+ mTrack.setPreferredDevice(info);
+ }
+ }
+
+ public void playAndMeasureRate() throws Exception {
+ final String TEST_NAME = "playAndMeasureRate";
+ final long TEST_DURATION_MILLIS = 5000; // just long enough to measure the rate
+ log(TEST_NAME, String.format("test using rate = %d, encoding = 0x%08x",
+ mSampleRate, mEncoding));
+ // Create a track and prime it.
+ mTrack = createAudioTrack(mSampleRate, mEncoding, mChannelConfig);
+ try {
+ assertEquals(TEST_NAME + ": track created", AudioTrack.STATE_INITIALIZED,
+ mTrack.getState());
+
+ if (USE_PREFERRED_DEVICE) {
+ usePreferredDevice();
+ }
+
+ int bytesWritten = 0;
+ mOffset = primeBuffer(); // prime the buffer
+ assertTrue(TEST_NAME + ": priming offset = " + mOffset, mOffset > 0);
+ bytesWritten += mOffset;
+
+ // Play for a while.
+ mTrack.play();
+ long elapsedMillis = 0;
+ long startTime = System.currentTimeMillis();
+ while (elapsedMillis < TEST_DURATION_MILLIS) {
+ writeBlock(mBlockSize);
+ elapsedMillis = System.currentTimeMillis() - startTime;
+ mTimestampAnalyzer.addTimestamp(mTrack);
+ }
+
+ // Did we underrun? Allow 0 or 1 because there is sometimes
+ // an underrun on startup.
+ int underrunCount1 = mTrack.getUnderrunCount();
+ assertTrue(TEST_NAME + ": too many underruns, got underrunCount1",
+ underrunCount1 < 2);
+
+ // Estimate the sample rate and compare it with expected.
+ double estimatedRate = mTimestampAnalyzer.estimateSampleRate();
+ assertEquals(TEST_NAME + ": measured sample rate",
+ mSampleRate, estimatedRate, MAX_RATE_TOLERANCE_HZ);
+ } finally {
+ mTrack.release();
+ }
+ }
+ }
+
+ // Create player for short[]
+ class SamplePlayerShorts extends SamplePlayerBase {
+ private final short[] mData;
+
+ SamplePlayerShorts(int sampleRate, int encoding, int channelConfig) {
+ super(sampleRate, encoding, channelConfig);
+ mData = new short[64 * 1024];
+ // Fill with noise. We should not hear the noise for IEC61937.
+ int amplitude = 8000;
+ Random random = new Random();
+ for (int i = 0; i < mData.length; i++) {
+ mData[i] = (short)(random.nextInt(amplitude) - (amplitude / 2));
+ }
+ }
+
+ SamplePlayerShorts(int sampleRate, int encoding, int channelConfig, @RawRes int resourceId)
+ throws Exception {
+ super(sampleRate, encoding, channelConfig);
+ mData = loadRawResourceShorts(resourceId);
+ assertTrue("SamplePlayerShorts: load resource file as shorts", mData.length > 0);
+ }
+
+ @Override
+ protected int writeBlock(int numShorts) {
+ int result = 0;
+ int shortsToWrite = numShorts;
+ int shortsLeft = mData.length - mOffset;
+ if (shortsToWrite > shortsLeft) {
+ shortsToWrite = shortsLeft;
+ }
+ if (shortsToWrite > 0) {
+ result = mTrack.write(mData, mOffset, shortsToWrite);
+ mOffset += result;
+ } else {
+ mOffset = 0; // rewind
+ }
+ return result;
+ }
+ }
+
+ // Create player for byte[]
+ class SamplePlayerBytes extends SamplePlayerBase {
+ private final byte[] mData;
+
+ SamplePlayerBytes(int sampleRate, int encoding, int channelConfig) {
+ super(sampleRate, encoding, channelConfig);
+ mData = new byte[128 * 1024];
+ }
+
+ SamplePlayerBytes(int sampleRate, int encoding, int channelConfig, @RawRes int resourceId)
+ throws Exception {
+ super(sampleRate, encoding, channelConfig);
+ mData = loadRawResourceBytes(resourceId);
+ assertTrue("SamplePlayerBytes: load resource file as bytes", mData.length > 0);
+ }
+
+ @Override
+ protected int writeBlock(int numBytes) {
+ int result = 0;
+ int bytesToWrite = numBytes;
+ int bytesLeft = mData.length - mOffset;
+ if (bytesToWrite > bytesLeft) {
+ bytesToWrite = bytesLeft;
+ }
+ if (bytesToWrite > 0) {
+ result = mTrack.write(mData, mOffset, bytesToWrite);
+ mOffset += result;
+ } else {
+ mOffset = 0; // rewind
+ }
+ return result;
+ }
+ }
+
+ public void testPlayAC3Bytes() throws Exception {
+ if (mInfoAC3 != null) {
+ SamplePlayerBytes player = new SamplePlayerBytes(
+ 48000, AudioFormat.ENCODING_AC3, AudioFormat.CHANNEL_OUT_STEREO,
+ RES_AC3_VOICE_48000);
+ player.playAndMeasureRate();
+ }
+ }
+
+ public void testPlayAC3Shorts() throws Exception {
+ if (mInfoAC3 != null) {
+ SamplePlayerShorts player = new SamplePlayerShorts(
+ 48000, AudioFormat.ENCODING_AC3, AudioFormat.CHANNEL_OUT_STEREO,
+ RES_AC3_VOICE_48000);
+ player.playAndMeasureRate();
+ }
+ }
+
+ // Note that for testing IEC61937, the Audio framework does not look at the
+ // wrapped data. It just passes it through over HDMI. See we can just use
+ // zeros instead of real data.
+ public void testPlayIEC61937_32000() throws Exception {
+ if (mInfoIEC61937 != null) {
+ SamplePlayerShorts player = new SamplePlayerShorts(
+ 32000, AudioFormat.ENCODING_IEC61937, AudioFormat.CHANNEL_OUT_STEREO);
+ player.playAndMeasureRate();
+ }
+ }
+
+ public void testPlayIEC61937_44100() throws Exception {
+ if (mInfoIEC61937 != null) {
+ SamplePlayerShorts player = new SamplePlayerShorts(
+ 44100, AudioFormat.ENCODING_IEC61937, AudioFormat.CHANNEL_OUT_STEREO);
+ player.playAndMeasureRate();
+ }
+ }
+
+ public void testPlayIEC61937_48000() throws Exception {
+ if (mInfoIEC61937 != null) {
+ SamplePlayerShorts player = new SamplePlayerShorts(
+ 48000, AudioFormat.ENCODING_IEC61937, AudioFormat.CHANNEL_OUT_STEREO);
+ player.playAndMeasureRate();
+ }
+ }
+
+ public void testIEC61937_Errors() throws Exception {
+ if (mInfoIEC61937 != null) {
+ final String TEST_NAME = "testIEC61937_Errors";
+ try {
+ AudioTrack track = createAudioTrack(48000, AudioFormat.ENCODING_IEC61937,
+ AudioFormat.CHANNEL_OUT_MONO);
+ assertTrue(TEST_NAME + ": IEC61937 track creation should fail for mono", false);
+ } catch (IllegalArgumentException e) {
+ // This is expected behavior.
+ }
+
+ try {
+ AudioTrack track = createAudioTrack(48000, AudioFormat.ENCODING_IEC61937,
+ AudioFormat.CHANNEL_OUT_5POINT1);
+ assertTrue(TEST_NAME + ": IEC61937 track creation should fail for 5.1", false);
+ } catch (IllegalArgumentException e) {
+ // This is expected behavior.
+ }
+ }
+ }
+
+ public void testPlaySineSweepShorts() throws Exception {
+ SamplePlayerShorts player = new SamplePlayerShorts(
+ 44100, AudioFormat.ENCODING_PCM_16BIT, AudioFormat.CHANNEL_OUT_STEREO,
+ R.raw.sinesweepraw);
+ player.playAndMeasureRate();
+ }
+
+ public void testPlaySineSweepBytes() throws Exception {
+ SamplePlayerBytes player = new SamplePlayerBytes(
+ 44100, AudioFormat.ENCODING_PCM_16BIT, AudioFormat.CHANNEL_OUT_STEREO,
+ R.raw.sinesweepraw);
+ player.playAndMeasureRate();
+ }
+
+ public void testPlaySineSweepBytes48000() throws Exception {
+ SamplePlayerBytes player = new SamplePlayerBytes(
+ 48000, AudioFormat.ENCODING_PCM_16BIT, AudioFormat.CHANNEL_OUT_STEREO,
+ R.raw.sinesweepraw);
+ player.playAndMeasureRate();
+ }
+
+ public void testPlaySineSweepShortsMono() throws Exception {
+ SamplePlayerShorts player = new SamplePlayerShorts(44100, AudioFormat.ENCODING_PCM_16BIT,
+ AudioFormat.CHANNEL_OUT_MONO,
+ R.raw.sinesweepraw);
+ player.playAndMeasureRate();
+ }
+
+ public void testPlaySineSweepBytesMono()
+ throws Exception {
+ SamplePlayerBytes player = new SamplePlayerBytes(44100,
+ AudioFormat.ENCODING_PCM_16BIT, AudioFormat.CHANNEL_OUT_MONO, R.raw.sinesweepraw);
+ player.playAndMeasureRate();
+ }
+
+}
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackTest.java b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
index 169434c..d81c11c 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrackTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
@@ -1961,11 +1961,10 @@
.setEncoding(encoding)
.setSampleRate(sampleRate)
.build();
+ // not specifying the buffer size in the builder should get us the minimum buffer size.
AudioTrack track = new AudioTrack.Builder()
.setAudioAttributes(attributes)
.setAudioFormat(format)
- .setBufferSizeInBytes(AudioTrack.getMinBufferSize(
- sampleRate, channelMask, encoding))
.setTransferMode(transferMode)
.build();
assertEquals(AudioTrack.STATE_INITIALIZED, track.getState());
diff --git a/tests/tests/net/src/android/net/wifi/cts/NsdManagerTest.java b/tests/tests/net/src/android/net/wifi/cts/NsdManagerTest.java
index e132cce..2e2e75b 100644
--- a/tests/tests/net/src/android/net/wifi/cts/NsdManagerTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/NsdManagerTest.java
@@ -24,6 +24,7 @@
import java.io.IOException;
import java.net.ServerSocket;
+import java.util.Arrays;
import java.util.Random;
import java.util.List;
import java.util.ArrayList;
@@ -41,6 +42,7 @@
NsdManager.RegistrationListener mRegistrationListener;
NsdManager.DiscoveryListener mDiscoveryListener;
NsdManager.ResolveListener mResolveListener;
+ private NsdServiceInfo mResolvedService;
public NsdManagerTest() {
initRegistrationListener();
@@ -119,6 +121,7 @@
@Override
public void onServiceResolved(NsdServiceInfo serviceInfo) {
+ mResolvedService = serviceInfo;
setEvent("onServiceResolved", serviceInfo);
}
};
@@ -254,14 +257,87 @@
if (DBG) Log.d(TAG, "Tear down test ...");
}
- public void runTest() throws Exception {
+ public void testNDSManager() throws Exception {
+ EventData lastEvent = null;
+
+ if (DBG) Log.d(TAG, "Starting test ...");
+
NsdServiceInfo si = new NsdServiceInfo();
si.setServiceType(SERVICE_TYPE);
si.setServiceName(mServiceName);
- EventData lastEvent = null;
+ byte testByteArray[] = new byte[] {-128, 127, 2, 1, 0, 1, 2};
+ String String256 = "1_________2_________3_________4_________5_________6_________" +
+ "7_________8_________9_________10________11________12________13________" +
+ "14________15________16________17________18________19________20________" +
+ "21________22________23________24________25________123456";
- if (DBG) Log.d(TAG, "Starting test ...");
+ // Illegal attributes
+ try {
+ si.setAttribute(null, (String) null);
+ fail("Could set null key");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ si.setAttribute("", (String) null);
+ fail("Could set empty key");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ si.setAttribute(String256, (String) null);
+ fail("Could set key with 255 characters");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ si.setAttribute("key", String256.substring(3));
+ fail("Could set key+value combination with more than 255 characters");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ si.setAttribute("key", String256.substring(4));
+ fail("Could set key+value combination with 255 characters");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ si.setAttribute(new String(new byte[]{0x19}), (String) null);
+ fail("Could set key with invalid character");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ si.setAttribute("=", (String) null);
+ fail("Could set key with invalid character");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ si.setAttribute(new String(new byte[]{0x7F}), (String) null);
+ fail("Could set key with invalid character");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ // Allowed attributes
+ si.setAttribute("booleanAttr", (String) null);
+ si.setAttribute("keyValueAttr", "value");
+ si.setAttribute("keyEqualsAttr", "=");
+ si.setAttribute(" whiteSpaceKeyValueAttr ", " value ");
+ si.setAttribute("binaryDataAttr", testByteArray);
+ si.setAttribute("nullBinaryDataAttr", (byte[]) null);
+ si.setAttribute("emptyBinaryDataAttr", new byte[]{});
+ si.setAttribute("longkey", String256.substring(9));
ServerSocket socket;
int localPort;
@@ -347,6 +423,25 @@
mNsdManager.resolveService(si, mResolveListener);
lastEvent = waitForCallback("onServiceResolved"); // id = 4
+ assertNotNull(mResolvedService);
+
+ // Check Txt attributes
+ assertEquals(8, mResolvedService.getAttributes().size());
+ assertTrue(mResolvedService.getAttributes().containsKey("booleanAttr"));
+ assertNull(mResolvedService.getAttributes().get("booleanAttr"));
+ assertEquals("value", new String(mResolvedService.getAttributes().get("keyValueAttr")));
+ assertEquals("=", new String(mResolvedService.getAttributes().get("keyEqualsAttr")));
+ assertEquals(" value ", new String(mResolvedService.getAttributes()
+ .get(" whiteSpaceKeyValueAttr ")));
+ assertEquals(String256.substring(9), new String(mResolvedService.getAttributes()
+ .get("longkey")));
+ assertTrue(Arrays.equals(testByteArray,
+ mResolvedService.getAttributes().get("binaryDataAttr")));
+ assertTrue(mResolvedService.getAttributes().containsKey("nullBinaryDataAttr"));
+ assertNull(mResolvedService.getAttributes().get("nullBinaryDataAttr"));
+ assertTrue(mResolvedService.getAttributes().containsKey("emptyBinaryDataAttr"));
+ assertNull(mResolvedService.getAttributes().get("emptyBinaryDataAttr"));
+
assertTrue(lastEvent != null);
assertTrue(lastEvent.mSucceeded);
@@ -394,7 +489,41 @@
registeredName = lastEvent.mInfo.getServiceName();
// Expect a record to be discovered
- lastEvent = waitForCallback("onServiceFound"); // id = 8
+ // Expect a service record to be discovered (and filter the ones
+ // that are unrelated to this test)
+ found = false;
+ for (int i = 0; i < 32; i++) {
+
+ lastEvent = waitForCallback("onServiceFound"); // id = 8
+ if (lastEvent == null) {
+ // no more onServiceFound events are being reported!
+ break;
+ }
+
+ assertTrue(lastEvent.mSucceeded);
+
+ if (DBG) Log.d(TAG, "id = " + String.valueOf(mWaitId) + ": ServiceName = " +
+ lastEvent.mInfo.getServiceName());
+
+ if (lastEvent.mInfo.getServiceName().equals(registeredName)) {
+ // Save it, as it will get overwritten with new serviceFound events
+ si = lastEvent.mInfo;
+ found = true;
+ }
+
+ // Remove this event from the event cache, so it won't be found by subsequent
+ // calls to waitForCallback
+ synchronized (mEventCache) {
+ mEventCache.remove(lastEvent);
+ }
+ }
+
+ assertTrue(found);
+
+ // Resolve the service
+ clearEventCache();
+ mNsdManager.resolveService(si, mResolveListener);
+ lastEvent = waitForCallback("onServiceResolved"); // id = 9
assertTrue(lastEvent != null);
assertTrue(lastEvent.mSucceeded);
@@ -404,11 +533,16 @@
assertTrue(lastEvent.mInfo.getServiceName().equals(registeredName));
+ assertNotNull(mResolvedService);
+
+ // Check that we don't have any TXT records
+ assertEquals(0, mResolvedService.getAttributes().size());
+
checkForAdditionalEvents();
clearEventCache();
mNsdManager.stopServiceDiscovery(mDiscoveryListener);
- lastEvent = waitForCallback("onDiscoveryStopped"); // id = 9
+ lastEvent = waitForCallback("onDiscoveryStopped"); // id = 10
assertTrue(lastEvent != null);
assertTrue(lastEvent.mSucceeded);
assertTrue(checkCacheSize(1));
@@ -418,7 +552,7 @@
mNsdManager.unregisterService(mRegistrationListener);
- lastEvent = waitForCallback("onServiceUnregistered"); // id = 10
+ lastEvent = waitForCallback("onServiceUnregistered"); // id = 11
assertTrue(lastEvent != null);
assertTrue(lastEvent.mSucceeded);
assertTrue(checkCacheSize(1));
diff --git a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
index a8e8e64..90473d7 100644
--- a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
+++ b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
@@ -241,11 +241,22 @@
} catch (NotFoundException e) {
fail("Failed to load resource with id: " + rawResId);
}
- FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
- | FileUtils.S_IRWXO);
assertTrue(FileUtils.copyToFile(is, outFile));
- FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
- | FileUtils.S_IRWXO);
+ exposeFile(outFile);
+ }
+
+ private File exposeFile(File file) {
+ file.setReadable(true, false);
+ file.setReadable(true, true);
+
+ File dir = file.getParentFile();
+ do {
+ dir.setExecutable(true, false);
+ dir.setExecutable(true, true);
+ dir = dir.getParentFile();
+ } while (dir != null);
+
+ return file;
}
private String mountObb(final int resource, final File file, int expectedState) {
diff --git a/tests/tests/print/src/android/print/cts/BasePrintTest.java b/tests/tests/print/src/android/print/cts/BasePrintTest.java
index 038b572..44f9ff1 100644
--- a/tests/tests/print/src/android/print/cts/BasePrintTest.java
+++ b/tests/tests/print/src/android/print/cts/BasePrintTest.java
@@ -550,7 +550,8 @@
}
if (onRequestCustomPrinterIcon != null) {
doAnswer(onRequestCustomPrinterIcon).when(callbacks).onRequestCustomPrinterIcon(
- any(PrinterId.class), any(CustomPrinterIconCallback.class));
+ any(PrinterId.class), any(CancellationSignal.class),
+ any(CustomPrinterIconCallback.class));
}
if (onStopPrinterStateTracking != null) {
doAnswer(onStopPrinterStateTracking).when(callbacks).onStopPrinterStateTracking(
diff --git a/tests/tests/print/src/android/print/cts/PrintServicesTest.java b/tests/tests/print/src/android/print/cts/PrintServicesTest.java
index 4422979..e1e17ff 100644
--- a/tests/tests/print/src/android/print/cts/PrintServicesTest.java
+++ b/tests/tests/print/src/android/print/cts/PrintServicesTest.java
@@ -200,7 +200,7 @@
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
CustomPrinterIconCallback callback = (CustomPrinterIconCallback) invocation
- .getArguments()[1];
+ .getArguments()[2];
if (mIcon != null) {
callback.onCustomPrinterIconLoaded(mIcon);
diff --git a/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java b/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
index a198790..00efa67 100644
--- a/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
+++ b/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
@@ -187,6 +187,7 @@
// Configure the print services.
FirstPrintService.setCallbacks(firstServiceCallbacks);
+ SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
// Create a print adapter that respects the print contract.
PrintDocumentAdapter adapter = createMockPrintDocumentAdapter();
diff --git a/tests/tests/print/src/android/print/cts/PrinterInfoTest.java b/tests/tests/print/src/android/print/cts/PrinterInfoTest.java
index db19d20..db09b24 100644
--- a/tests/tests/print/src/android/print/cts/PrinterInfoTest.java
+++ b/tests/tests/print/src/android/print/cts/PrinterInfoTest.java
@@ -367,7 +367,7 @@
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
CustomPrinterIconCallback callback = (CustomPrinterIconCallback) invocation
- .getArguments()[1];
+ .getArguments()[2];
if (mIcon != null) {
callback.onCustomPrinterIconLoaded(mIcon);
diff --git a/tests/tests/print/src/android/print/cts/services/PrinterDiscoverySessionCallbacks.java b/tests/tests/print/src/android/print/cts/services/PrinterDiscoverySessionCallbacks.java
index 2e0e729..ebddda1 100644
--- a/tests/tests/print/src/android/print/cts/services/PrinterDiscoverySessionCallbacks.java
+++ b/tests/tests/print/src/android/print/cts/services/PrinterDiscoverySessionCallbacks.java
@@ -16,6 +16,7 @@
package android.print.cts.services;
+import android.os.CancellationSignal;
import android.print.PrinterId;
import android.printservice.CustomPrinterIconCallback;
@@ -42,7 +43,7 @@
public abstract void onStartPrinterStateTracking(PrinterId printerId);
public abstract void onRequestCustomPrinterIcon(PrinterId printerId,
- CustomPrinterIconCallback callback);
+ CancellationSignal cancellationSignal, CustomPrinterIconCallback callback);
public abstract void onStopPrinterStateTracking(PrinterId printerId);
diff --git a/tests/tests/print/src/android/print/cts/services/StubbablePrinterDiscoverySession.java b/tests/tests/print/src/android/print/cts/services/StubbablePrinterDiscoverySession.java
index 4c2d8b8..b7cccaa 100644
--- a/tests/tests/print/src/android/print/cts/services/StubbablePrinterDiscoverySession.java
+++ b/tests/tests/print/src/android/print/cts/services/StubbablePrinterDiscoverySession.java
@@ -16,6 +16,7 @@
package android.print.cts.services;
+import android.os.CancellationSignal;
import android.print.PrinterId;
import android.printservice.CustomPrinterIconCallback;
import android.printservice.PrintService;
@@ -70,9 +71,9 @@
@Override
public void onRequestCustomPrinterIcon(PrinterId printerId,
- CustomPrinterIconCallback callback) {
+ CancellationSignal cancellationSignal, CustomPrinterIconCallback callback) {
if (mCallbacks != null) {
- mCallbacks.onRequestCustomPrinterIcon(printerId, callback);
+ mCallbacks.onRequestCustomPrinterIcon(printerId, cancellationSignal, callback);
}
}
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java
index 3ccc61b..8fe95f5 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_FilesTest.java
@@ -278,16 +278,6 @@
} catch (FileNotFoundException e) {
// expected
}
- // now make the file world-readable
- fos = mContext.openFileOutput("dummy.dat", Context.MODE_WORLD_READABLE);
- fos.write(0);
- fos.close();
- try {
- pfd = mResolver.openFileDescriptor(uri, "r");
- pfd.close();
- } catch (FileNotFoundException e) {
- fail("failed to open file");
- }
path.delete();
File sdfile = null;
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/GetAllocationTest.java b/tests/tests/renderscript/src/android/renderscript/cts/GetAllocationTest.java
index f938569..177a804 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/GetAllocationTest.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/GetAllocationTest.java
@@ -37,7 +37,6 @@
Allocation mOut = Allocation.createTyped(mRS, mTemp.getType());
ms.bind_pointer(mTemp);
- ms.set_script(ms);
ms.set_alloc_out(mOut);
ms.invoke_start();
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/get_allocation.rs b/tests/tests/renderscript/src/android/renderscript/cts/get_allocation.rs
index 01cb47c..ae7d3e6 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/get_allocation.rs
+++ b/tests/tests/renderscript/src/android/renderscript/cts/get_allocation.rs
@@ -2,7 +2,6 @@
#pragma rs java_package_name(android.renderscript.cts)
const int* pointer;
-rs_script script;
rs_allocation alloc_in;
rs_allocation alloc_out;
diff --git a/tests/tests/security/src/android/security/cts/BrowserTest.java b/tests/tests/security/src/android/security/cts/BrowserTest.java
index 223f83f..0948713 100644
--- a/tests/tests/security/src/android/security/cts/BrowserTest.java
+++ b/tests/tests/security/src/android/security/cts/BrowserTest.java
@@ -16,23 +16,22 @@
package android.security.cts;
-import android.content.ComponentName;
-import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
+import android.os.StrictMode;
import android.test.AndroidTestCase;
import android.webkit.cts.CtsTestServer;
+import org.apache.http.HttpEntity;
+
+import java.io.File;
import java.io.FileOutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-import org.apache.http.HttpEntity;
/**
* Test file for browser security issues.
*/
@@ -138,6 +137,8 @@
* See Bug 6212665 for detailed information about this issue.
*/
public void testBrowserPrivateDataAccess() throws Throwable {
+ // Yucky workaround to let us launch file:// Uris
+ StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().build());
// Create a list of all intents for http display. This includes all browsers.
List<Intent> intents = createAllIntents(Uri.parse("http://www.google.com"));
@@ -146,8 +147,10 @@
for (Intent intent : intents) {
// reset state
mWebServer.resetRequestState();
+
// define target file, which is supposedly protected from this app
- String targetFile = "file://" + getTargetFilePath();
+ final File secretFile = exposeFile(stageFile("target.txt", "SECRETS!"));
+
String html =
"<html><body>\n" +
" <form name=\"myform\" action=" + action + " method=\"post\">\n" +
@@ -155,7 +158,7 @@
" <a href=\"javascript :submitform()\">Search</a></form>\n" +
"<script>\n" +
" var client = new XMLHttpRequest();\n" +
- " client.open('GET', '" + targetFile + "');\n" +
+ " client.open('GET', '" + Uri.fromFile(secretFile) + "');\n" +
" client.onreadystatechange = function() {\n" +
" if(client.readyState == 4) {\n" +
" myform.val.value = client.responseText;\n" +
@@ -163,20 +166,14 @@
" }}\n" +
" client.send();\n" +
"</script></body></html>\n";
- String filename = "jsfileaccess.html";
- // create a local HTML to access protected file
- FileOutputStream out = mContext.openFileOutput(filename,
- mContext.MODE_WORLD_READABLE);
- Writer writer = new OutputStreamWriter(out, "UTF-8");
- writer.write(html);
- writer.flush();
- writer.close();
- String filepath = mContext.getFileStreamPath(filename).getAbsolutePath();
- Uri uri = Uri.parse("file://" + filepath);
+ // create a local HTML to access protected file
+ final File htmlFile = exposeFile(stageFile("jsfileaccess.html", html));
+
// do a file request
- intent.setData(uri);
+ intent.setData(Uri.fromFile(htmlFile));
mContext.startActivity(intent);
+
/*
* Wait 5 seconds for the browser to contact the server, but
* fail fast if we detect the bug
@@ -199,14 +196,26 @@
}
}
- private String getTargetFilePath() throws Exception {
- FileOutputStream out = mContext.openFileOutput("target.txt",
- mContext.MODE_WORLD_READABLE);
- Writer writer = new OutputStreamWriter(out, "UTF-8");
- writer.write("testing");
- writer.flush();
- writer.close();
- return mContext.getFileStreamPath("target.txt").getAbsolutePath();
+ private File stageFile(String name, String contents) throws Exception {
+ final File file = mContext.getFileStreamPath(name);
+ try (FileOutputStream out = new FileOutputStream(file)) {
+ out.write(contents.getBytes(StandardCharsets.UTF_8));
+ }
+ return file;
+ }
+
+ private File exposeFile(File file) throws Exception {
+ file.setReadable(true, false);
+ file.setReadable(true, true);
+
+ File dir = file.getParentFile();
+ do {
+ dir.setExecutable(true, false);
+ dir.setExecutable(true, true);
+ dir = dir.getParentFile();
+ } while (dir != null);
+
+ return file;
}
/**
diff --git a/tests/tests/text/src/android/text/cts/BoringLayoutTest.java b/tests/tests/text/src/android/text/cts/BoringLayoutTest.java
index 714fc33..36d2f93 100644
--- a/tests/tests/text/src/android/text/cts/BoringLayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/BoringLayoutTest.java
@@ -22,6 +22,7 @@
import android.graphics.Bitmap.Config;
import android.test.AndroidTestCase;
import android.text.BoringLayout;
+import android.text.BoringLayout.Metrics;
import android.text.Layout;
import android.text.TextPaint;
import android.text.TextUtils;
@@ -41,7 +42,7 @@
private static final CharSequence DEFAULT_CHAR_SEQUENCE = "default";
private static final TextPaint DEFAULT_PAINT = new TextPaint();
private static final Layout.Alignment DEFAULT_ALIGN = Layout.Alignment.ALIGN_CENTER;
- private static final BoringLayout.Metrics DEFAULT_METRICS = createMetrics(
+ private static final Metrics DEFAULT_METRICS = createMetrics(
METRICS_TOP,
METRICS_ASCENT,
METRICS_DESCENT,
@@ -216,7 +217,7 @@
TextPaint paint = new TextPaint();
assertNotNull(BoringLayout.isBoring("hello android", paint));
- BoringLayout.Metrics metrics = new BoringLayout.Metrics();
+ Metrics metrics = new Metrics();
metrics.width = 100;
assertNotNull(BoringLayout.isBoring("hello android", paint, metrics));
@@ -228,6 +229,31 @@
assertNull(BoringLayout.isBoring("hello android\n\n\n", paint));
}
+ public void testIsBoring_resetsFontMetrics() {
+ int someInt = 100;
+ String text = "some text";
+
+ TextPaint paint = new TextPaint();
+ Paint.FontMetricsInt paintMetrics = paint.getFontMetricsInt();
+ Metrics changedMetrics = new Metrics();
+ changedMetrics.top = paintMetrics.top - someInt;
+ changedMetrics.ascent = paintMetrics.ascent - someInt;
+ changedMetrics.bottom = paintMetrics.bottom + someInt;
+ changedMetrics.descent = paintMetrics.descent + someInt;
+ changedMetrics.leading = paintMetrics.leading + someInt;
+
+ Metrics expectedMetrics = BoringLayout.isBoring(text, paint, (Metrics) null);
+ Metrics actualMetrics = BoringLayout.isBoring(text, paint, changedMetrics);
+
+ assertNotNull(actualMetrics);
+ assertNotNull(expectedMetrics);
+ assertEquals(expectedMetrics.top, actualMetrics.top);
+ assertEquals(expectedMetrics.ascent, actualMetrics.ascent);
+ assertEquals(expectedMetrics.bottom, actualMetrics.bottom);
+ assertEquals(expectedMetrics.descent, actualMetrics.descent);
+ assertEquals(expectedMetrics.leading, actualMetrics.leading);
+ }
+
public void testGetLineDirections() {
assertNotNull(mBoringLayout.getLineDirections(0));
assertNotNull(mBoringLayout.getLineDirections(2));
@@ -288,7 +314,7 @@
}
}
- private static BoringLayout.Metrics createMetrics(
+ private static Metrics createMetrics(
final int top,
final int ascent,
final int descent,
@@ -296,7 +322,7 @@
final int width,
final int leading) {
- final BoringLayout.Metrics metrics = new BoringLayout.Metrics();
+ final Metrics metrics = new Metrics();
metrics.top = top;
metrics.ascent = ascent;
diff --git a/tests/tests/view/src/android/view/cts/WindowTest.java b/tests/tests/view/src/android/view/cts/WindowTest.java
index bfeb137..439eda5 100644
--- a/tests/tests/view/src/android/view/cts/WindowTest.java
+++ b/tests/tests/view/src/android/view/cts/WindowTest.java
@@ -1046,7 +1046,7 @@
}
@Override
- public void onMultiWindowChanged() {
+ public void onMultiWindowModeChanged() {
}
@Override
diff --git a/tests/tests/view/src/android/view/inputmethod/cts/InputConnectionWrapperTest.java b/tests/tests/view/src/android/view/inputmethod/cts/InputConnectionWrapperTest.java
index b939346..1ddfd2b 100644
--- a/tests/tests/view/src/android/view/inputmethod/cts/InputConnectionWrapperTest.java
+++ b/tests/tests/view/src/android/view/inputmethod/cts/InputConnectionWrapperTest.java
@@ -89,6 +89,8 @@
assertTrue(inputConnection.isSetComposingRegionCalled);
wrapper.requestCursorUpdates(InputConnection.CURSOR_UPDATE_IMMEDIATE);
assertTrue(inputConnection.isRequestCursorUpdatesCalled);
+ wrapper.closeConnection();
+ assertTrue(inputConnection.isCloseConnectionCalled);
assertFalse(inputConnection.isGetHandlerCalled);
assertNull(inputConnection.getHandler());
assertTrue(inputConnection.isGetHandlerCalled);
@@ -119,6 +121,7 @@
public boolean isSetSelectionCalled;
public boolean isRequestCursorUpdatesCalled;
public boolean isGetHandlerCalled;
+ public boolean isCloseConnectionCalled;
public boolean beginBatchEdit() {
isBeginBatchEditCalled = true;
@@ -239,5 +242,9 @@
isGetHandlerCalled = true;
return null;
}
+
+ public void closeConnection() {
+ isCloseConnectionCalled = true;
+ }
}
}
diff --git a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
index 1149d3b..afdc869 100644
--- a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
@@ -16,6 +16,7 @@
package android.widget.cts;
+import android.widget.FrameLayout;
import android.widget.cts.R;
@@ -30,14 +31,14 @@
import android.test.UiThreadTest;
import android.util.AttributeSet;
import android.util.Xml;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.MeasureSpec;
-import android.view.ViewGroup.LayoutParams;
import android.widget.HorizontalScrollView;
import android.widget.TextView;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
/**
* Test {@link HorizontalScrollView}.
@@ -332,6 +333,182 @@
assertEquals(30, child.getMeasuredWidth());
}
+ public void testMeasureSpecs() {
+ MyView child = spy(new MyView(mActivity));
+ MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
+ scrollView.addView(child);
+
+ scrollView.measureChild(child, MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
+ verify(child).onMeasure(
+ eq(MeasureSpec.makeMeasureSpec(100, MeasureSpec.UNSPECIFIED)),
+ eq(MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY)));
+ }
+
+ public void testMeasureSpecsWithPadding() {
+ MyView child = spy(new MyView(mActivity));
+ MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
+ scrollView.setPadding(3, 5, 7, 11);
+ scrollView.addView(child);
+
+ scrollView.measureChild(child, MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
+ verify(child).onMeasure(
+ eq(MeasureSpec.makeMeasureSpec(90, MeasureSpec.UNSPECIFIED)),
+ eq(MeasureSpec.makeMeasureSpec(134, MeasureSpec.EXACTLY)));
+ }
+
+ public void testMeasureSpecsWithMargins() {
+ MyView child = spy(new MyView(mActivity));
+ MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
+ scrollView.addView(child);
+
+ scrollView.measureChildWithMargins(child,
+ MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 15,
+ MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY), 20);
+ verify(child).onMeasure(
+ eq(MeasureSpec.makeMeasureSpec(85, MeasureSpec.UNSPECIFIED)),
+ eq(MeasureSpec.makeMeasureSpec(130, MeasureSpec.EXACTLY)));
+ }
+
+ public void testMeasureSpecsWithMarginsAndPadding() {
+ MyView child = spy(new MyView(mActivity));
+ MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
+ scrollView.setPadding(3, 5, 7, 11);
+ scrollView.addView(child);
+
+ scrollView.measureChildWithMargins(child,
+ MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 15,
+ MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY), 20);
+ verify(child).onMeasure(
+ eq(MeasureSpec.makeMeasureSpec(75, MeasureSpec.UNSPECIFIED)),
+ eq(MeasureSpec.makeMeasureSpec(114, MeasureSpec.EXACTLY)));
+ }
+
+ public void testMeasureSpecsWithMarginsAndNoHintWidth() {
+ MyView child = spy(new MyView(mActivity));
+ MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
+ scrollView.addView(child);
+
+ scrollView.measureChildWithMargins(child,
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 15,
+ MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY), 20);
+ verify(child).onMeasure(
+ eq(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)),
+ eq(MeasureSpec.makeMeasureSpec(130, MeasureSpec.EXACTLY)));
+ }
+
+ public void testFillViewport() {
+ MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
+
+ MyView child = new MyView(mActivity);
+ scrollView.setFillViewport(true);
+ child.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ ));
+
+ scrollView.addView(child);
+ scrollView.measure(MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY));
+
+ assertEquals(150, child.getMeasuredWidth());
+ assertEquals(100, child.getMeasuredHeight());
+
+ scrollView.layout(0, 0, 150, 100);
+ assertEquals(0, child.getLeft());
+ }
+
+ public void testFillViewportWithScrollViewPadding() {
+ MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
+ scrollView.setFillViewport(true);
+ scrollView.setPadding(3, 10, 5, 7);
+
+ MyView child = new MyView(mActivity);
+ child.setLayoutParams(new ViewGroup.LayoutParams(10,10));
+ child.setDesiredWidth(30);
+
+ scrollView.addView(child);
+ scrollView.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
+
+ assertEquals(92, child.getMeasuredWidth());
+ assertEquals(10, child.getMeasuredHeight());
+
+ scrollView.layout(0, 0, 100, 150);
+ assertEquals(3, child.getLeft());
+ }
+
+ public void testFillViewportWithChildMargins() {
+ MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
+ scrollView.setFillViewport(true);
+
+ MyView child = new MyView(mActivity);
+ FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(10, 10);
+ lp.leftMargin = 3;
+ lp.topMargin = 10;
+ lp.rightMargin = 5;
+ lp.bottomMargin = 7;
+ child.setDesiredWidth(30);
+ child.setLayoutParams(lp);
+
+ scrollView.addView(child);
+ scrollView.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
+
+ assertEquals(92, child.getMeasuredWidth());
+ assertEquals(10, child.getMeasuredHeight());
+
+ scrollView.layout(0, 0, 100, 150);
+ assertEquals(3, child.getLeft());
+ }
+
+ public void testFillViewportWithScrollViewPaddingAlreadyFills() {
+ MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
+ scrollView.setFillViewport(true);
+ scrollView.setPadding(3, 10, 5, 7);
+
+ MyView child = new MyView(mActivity);
+ child.setDesiredWidth(175);
+
+ scrollView.addView(child);
+ scrollView.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
+
+
+ assertEquals(175, child.getMeasuredWidth());
+ assertEquals(133, child.getMeasuredHeight());
+
+ scrollView.layout(0, 0, 100, 150);
+ assertEquals(3, child.getLeft());
+ }
+
+ public void testFillViewportWithChildMarginsAlreadyFills() {
+ MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
+ scrollView.setFillViewport(true);
+ MyView child = new MyView(mActivity);
+ FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+
+ lp.leftMargin = 3;
+ lp.topMargin = 10;
+ lp.rightMargin = 5;
+ lp.bottomMargin = 7;
+ child.setLayoutParams(lp);
+ child.setDesiredWidth(175);
+
+ scrollView.addView(child);
+ scrollView.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
+
+ assertEquals(175, child.getMeasuredWidth());
+ assertEquals(133, child.getMeasuredHeight());
+
+ scrollView.layout(0, 0, 100, 150);
+ assertEquals(3, child.getLeft());
+ }
+
@UiThreadTest
public void testPageScroll() {
mScrollView.setSmoothScrollingEnabled(false);
@@ -462,9 +639,9 @@
assertTrue(mScrollView.getChildCount() > 0);
assertEquals(ITEM_WIDTH * ITEM_COUNT, mScrollView.computeHorizontalScrollRange());
- MyScrollView myScrollView = new MyScrollView(mActivity);
- assertEquals(0, myScrollView.getChildCount());
- assertEquals(0, myScrollView.computeVerticalScrollRange());
+ MyHorizontalScrollView scrollView = new MyHorizontalScrollView(mActivity);
+ assertEquals(0, scrollView.getChildCount());
+ assertEquals(0, scrollView.computeHorizontalScrollRange());
}
@UiThreadTest
@@ -564,7 +741,7 @@
assertTrue(mScrollView.getRightFadingEdgeStrength() <= 1.0f);
assertTrue(mScrollView.getRightFadingEdgeStrength() >= 0.0f);
- MyScrollView myScrollView = new MyScrollView(mActivity);
+ MyHorizontalScrollView myScrollView = new MyHorizontalScrollView(mActivity);
assertEquals(0, myScrollView.getChildCount());
assertTrue(mScrollView.getLeftFadingEdgeStrength() <= 1.0f);
assertTrue(mScrollView.getLeftFadingEdgeStrength() >= 0.0f);
@@ -674,9 +851,31 @@
}.run();
}
- private static class MyView extends View {
+ public static class MyView extends View {
+ // measure in this height if set
+ private Integer mDesiredWidth;
public MyView(Context context) {
super(context);
}
+
+ public void setDesiredWidth(Integer desiredWidth) {
+ mDesiredWidth = desiredWidth;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ if (mDesiredWidth != null) {
+ int mode = MeasureSpec.getMode(widthMeasureSpec);
+ int size = MeasureSpec.getSize(widthMeasureSpec);
+ int newWidth = size;
+ if (mode == MeasureSpec.AT_MOST) {
+ newWidth = Math.max(size, mDesiredWidth);
+ } else if (mode == MeasureSpec.UNSPECIFIED) {
+ newWidth = mDesiredWidth;
+ }
+ setMeasuredDimension(newWidth, getMeasuredHeight());
+ }
+ }
}
}
diff --git a/tests/tests/widget/src/android/widget/cts/MyHorizontalScrollView.java b/tests/tests/widget/src/android/widget/cts/MyHorizontalScrollView.java
index 639193a..a5a0150 100644
--- a/tests/tests/widget/src/android/widget/cts/MyHorizontalScrollView.java
+++ b/tests/tests/widget/src/android/widget/cts/MyHorizontalScrollView.java
@@ -67,4 +67,19 @@
super.measureChildWithMargins(child, parentWidthMeasureSpec,
widthUsed, parentHeightMeasureSpec, heightUsed);
}
+
+ @Override
+ public int computeVerticalScrollRange() {
+ return super.computeVerticalScrollRange();
+ }
+
+ @Override
+ public int computeVerticalScrollOffset() {
+ return super.computeVerticalScrollOffset();
+ }
+
+ @Override
+ public int computeVerticalScrollExtent() {
+ return super.computeVerticalScrollExtent();
+ }
}
diff --git a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
index 2d58263..3054bab 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
@@ -246,8 +246,10 @@
runTestOnUiThread(() -> mPopupMenu.getMenu().performIdentifierAction(R.id.action_share, 0));
// Verify that our menu item click listener has been called on "share" action
+ // and that the dismiss listener hasn't been called just as a result of opening the submenu.
verify(mBuilder.mOnMenuItemClickListener, times(1)).onMenuItemClick(
mPopupMenu.getMenu().findItem(R.id.action_share));
+ verify(mBuilder.mOnDismissListener, never()).onDismiss(mPopupMenu);
runTestOnUiThread(() -> mPopupMenu.getMenu().findItem(R.id.action_share).getSubMenu().
performIdentifierAction(R.id.action_share_email, 0));
@@ -358,4 +360,4 @@
mPopupMenu.show();
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java b/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
index 0119cc0..26510f27 100644
--- a/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
@@ -16,6 +16,11 @@
package android.widget.cts;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.widget.FrameLayout;
import android.widget.cts.R;
@@ -34,7 +39,6 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.View.MeasureSpec;
-import android.view.ViewGroup.LayoutParams;
import android.widget.ScrollView;
import android.widget.TextView;
@@ -351,6 +355,179 @@
assertEquals(100, child.getMeasuredWidth());
}
+ public void testMeasureSpecs() {
+ MyView child = spy(new MyView(mActivity));
+ MyScrollView scrollView = new MyScrollView(mActivity);
+ scrollView.addView(child);
+
+ scrollView.measureChild(child, MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY));
+ verify(child).onMeasure(
+ eq(MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY)),
+ eq(MeasureSpec.makeMeasureSpec(100, MeasureSpec.UNSPECIFIED)));
+ }
+
+ public void testMeasureSpecsWithPadding() {
+ MyView child = spy(new MyView(mActivity));
+ MyScrollView scrollView = new MyScrollView(mActivity);
+ scrollView.setPadding(3, 5, 7, 11);
+ scrollView.addView(child);
+
+ scrollView.measureChild(child, MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY));
+ verify(child).onMeasure(
+ eq(MeasureSpec.makeMeasureSpec(140, MeasureSpec.EXACTLY)),
+ eq(MeasureSpec.makeMeasureSpec(84, MeasureSpec.UNSPECIFIED)));
+ }
+
+ public void testMeasureSpecsWithMargins() {
+ MyView child = spy(new MyView(mActivity));
+ MyScrollView scrollView = new MyScrollView(mActivity);
+ scrollView.addView(child);
+
+ scrollView.measureChildWithMargins(child,
+ MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY), 20,
+ MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 15);
+ verify(child).onMeasure(
+ eq(MeasureSpec.makeMeasureSpec(130, MeasureSpec.EXACTLY)),
+ eq(MeasureSpec.makeMeasureSpec(85, MeasureSpec.UNSPECIFIED)));
+ }
+
+ public void testMeasureSpecsWithMarginsAndPadding() {
+ MyView child = spy(new MyView(mActivity));
+ MyScrollView scrollView = new MyScrollView(mActivity);
+ scrollView.setPadding(3, 5, 7, 11);
+ scrollView.addView(child);
+
+ scrollView.measureChildWithMargins(child,
+ MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY), 20,
+ MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY), 15);
+ verify(child).onMeasure(
+ eq(MeasureSpec.makeMeasureSpec(120, MeasureSpec.EXACTLY)),
+ eq(MeasureSpec.makeMeasureSpec(69, MeasureSpec.UNSPECIFIED)));
+ }
+
+ public void testMeasureSpecsWithMarginsAndNoHintWidth() {
+ MyView child = spy(new MyView(mActivity));
+ MyScrollView scrollView = new MyScrollView(mActivity);
+ scrollView.addView(child);
+
+ scrollView.measureChildWithMargins(child,
+ MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY), 20,
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 15);
+ verify(child).onMeasure(
+ eq(MeasureSpec.makeMeasureSpec(130, MeasureSpec.EXACTLY)),
+ eq(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)));
+ }
+
+ public void testFillViewport() {
+ MyScrollView scrollView = new MyScrollView(mActivity);
+ scrollView.setFillViewport(true);
+
+ MyView child = new MyView(mActivity);
+ child.setLayoutParams(new ViewGroup.LayoutParams(100, 100));
+
+ scrollView.addView(child);
+ scrollView.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
+
+ assertEquals(150, child.getMeasuredHeight());
+ assertEquals(100, child.getMeasuredWidth());
+
+ scrollView.layout(0, 0, 100, 150);
+ assertEquals(0, child.getTop());
+ }
+
+ public void testFillViewportWithScrollViewPadding() {
+ MyScrollView scrollView = new MyScrollView(mActivity);
+ scrollView.setFillViewport(true);
+ scrollView.setPadding(3, 10, 5, 7);
+
+ MyView child = new MyView(mActivity);
+ child.setLayoutParams(new ViewGroup.LayoutParams(10,10));
+ child.setDesiredHeight(30);
+
+ scrollView.addView(child);
+ scrollView.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
+
+ assertEquals(133, child.getMeasuredHeight());
+ assertEquals(10, child.getMeasuredWidth());
+
+ scrollView.layout(0, 0, 100, 150);
+ assertEquals(10, child.getTop());
+ }
+
+ public void testFillViewportWithChildMargins() {
+ MyScrollView scrollView = new MyScrollView(mActivity);
+ scrollView.setFillViewport(true);
+
+ MyView child = new MyView(mActivity);
+ FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(10, 10);
+ lp.leftMargin = 3;
+ lp.topMargin = 10;
+ lp.rightMargin = 5;
+ lp.bottomMargin = 7;
+ child.setDesiredHeight(30);
+ child.setLayoutParams(lp);
+
+ scrollView.addView(child);
+ scrollView.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
+
+ assertEquals(133, child.getMeasuredHeight());
+ assertEquals(10, child.getMeasuredWidth());
+
+ scrollView.layout(0, 0, 100, 150);
+ assertEquals(10, child.getTop());
+ }
+
+ public void testFillViewportWithScrollViewPaddingAlreadyFills() {
+ MyScrollView scrollView = new MyScrollView(mActivity);
+ scrollView.setFillViewport(true);
+ scrollView.setPadding(3, 10, 5, 7);
+
+ MyView child = new MyView(mActivity);
+ child.setDesiredHeight(175);
+
+ scrollView.addView(child);
+ scrollView.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
+
+
+ assertEquals(92, child.getMeasuredWidth());
+ assertEquals(175, child.getMeasuredHeight());
+
+ scrollView.layout(0, 0, 100, 150);
+ assertEquals(10, child.getTop());
+ }
+
+ public void testFillViewportWithChildMarginsAlreadyFills() {
+ MyScrollView scrollView = new MyScrollView(mActivity);
+ scrollView.setFillViewport(true);
+ MyView child = new MyView(mActivity);
+ FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+
+ lp.leftMargin = 3;
+ lp.topMargin = 10;
+ lp.rightMargin = 5;
+ lp.bottomMargin = 7;
+ child.setLayoutParams(lp);
+ child.setDesiredHeight(175);
+
+ scrollView.addView(child);
+ scrollView.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(150, MeasureSpec.EXACTLY));
+
+ assertEquals(92, child.getMeasuredWidth());
+ assertEquals(175, child.getMeasuredHeight());
+
+ scrollView.layout(0, 0, 100, 150);
+ assertEquals(10, child.getTop());
+ }
+
@UiThreadTest
public void testPageScroll() {
mScrollView.setSmoothScrollingEnabled(false);
@@ -703,9 +880,31 @@
}.run();
}
- private static class MyView extends View {
+ public static class MyView extends View {
+ // measure in this height if set
+ private Integer mDesiredHeight;
public MyView(Context context) {
super(context);
}
+
+ public void setDesiredHeight(Integer desiredHeight) {
+ mDesiredHeight = desiredHeight;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ if (mDesiredHeight != null) {
+ int mode = MeasureSpec.getMode(heightMeasureSpec);
+ int size = MeasureSpec.getSize(heightMeasureSpec);
+ int newHeight = size;
+ if (mode == MeasureSpec.AT_MOST) {
+ newHeight = Math.max(size, mDesiredHeight);
+ } else if (mode == MeasureSpec.UNSPECIFIED) {
+ newHeight = mDesiredHeight;
+ }
+ setMeasuredDimension(getMeasuredWidth(), newHeight);
+ }
+ }
}
}
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index b4a68d8..40d42a2 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -42,9 +42,9 @@
import android.test.ActivityInstrumentationTestCase2;
import android.test.TouchUtils;
import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.Editable;
-import android.text.Html;
import android.text.InputFilter;
import android.text.InputType;
import android.text.Layout;
@@ -71,6 +71,7 @@
import android.text.method.TextKeyListener.Capitalize;
import android.text.method.TimeKeyListener;
import android.text.method.TransformationMethod;
+import android.text.style.ImageSpan;
import android.text.style.URLSpan;
import android.text.style.UnderlineSpan;
import android.text.util.Linkify;
@@ -1302,6 +1303,71 @@
}
}
+ @MediumTest
+ public void testSetText_updatesHeightAfterRemovingImageSpan() {
+ // Height calculation had problems when TextView had width: match_parent
+ final int textViewWidth = ViewGroup.LayoutParams.MATCH_PARENT;
+ final Spannable text = new SpannableString("some text");
+ final int spanHeight = 100;
+
+ // prepare TextView, width: MATCH_PARENT
+ TextView textView = new TextView(getActivity());
+ textView.setSingleLine(true);
+ textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 2);
+ textView.setPadding(0, 0, 0, 0);
+ textView.setIncludeFontPadding(false);
+ textView.setText(text);
+ final FrameLayout layout = new FrameLayout(mActivity);
+ final ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(textViewWidth,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+ layout.addView(textView, layoutParams);
+ layout.setLayoutParams(layoutParams);
+ mActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ getActivity().setContentView(layout);
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+
+ // measure height of text with no span
+ final int heightWithoutSpan = textView.getHeight();
+ assertTrue("Text height should be smaller than span height",
+ heightWithoutSpan < spanHeight);
+
+ // add ImageSpan to text
+ Drawable drawable = mInstrumentation.getContext().getDrawable(R.drawable.scenery);
+ drawable.setBounds(0, 0, spanHeight, spanHeight);
+ ImageSpan span = new ImageSpan(drawable);
+ text.setSpan(span, 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ mActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ textView.setText(text);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+
+ // measure height with span
+ final int heightWithSpan = textView.getHeight();
+ assertTrue("Text height should be greater or equal than span height",
+ heightWithSpan >= spanHeight);
+
+ // remove the span
+ text.removeSpan(span);
+ mActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ textView.setText(text);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+
+ final int heightAfterRemoveSpan = textView.getHeight();
+ assertEquals("Text height should be same after removing the span",
+ heightWithoutSpan, heightAfterRemoveSpan);
+ }
+
public void testRemoveSelectionWithSelectionHandles() {
initTextViewForTyping();
diff --git a/tools/selinux/SELinuxNeverallowTestFrame.py b/tools/selinux/SELinuxNeverallowTestFrame.py
index 6f2613b..ee14116 100644
--- a/tools/selinux/SELinuxNeverallowTestFrame.py
+++ b/tools/selinux/SELinuxNeverallowTestFrame.py
@@ -18,25 +18,22 @@
package android.cts.security;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceTestCase;
import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.testtype.IDeviceTest;
import java.io.BufferedReader;
import java.io.File;
-import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
-import java.io.FileOutputStream;
-import java.lang.String;
-import java.net.URL;
-import java.util.Scanner;
/**
* Neverallow Rules SELinux tests.
*/
-public class SELinuxNeverallowRulesTest extends DeviceTestCase {
+public class SELinuxNeverallowRulesTest extends DeviceTestCase implements IBuildReceiver, IDeviceTest {
private File sepolicyAnalyze;
private File devicePolicyFile;
@@ -45,27 +42,28 @@
*/
private ITestDevice mDevice;
- private File copyResourceToTempFile(String resName) throws IOException {
- InputStream is = this.getClass().getResourceAsStream(resName);
- File tempFile = File.createTempFile("SELinuxHostTest", ".tmp");
- FileOutputStream os = new FileOutputStream(tempFile);
- int rByte = 0;
- while ((rByte = is.read()) != -1) {
- os.write(rByte);
- }
- os.flush();
- os.close();
- tempFile.deleteOnExit();
- return tempFile;
+ private CompatibilityBuildHelper mHelper;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setBuild(IBuildInfo build) {
+ mHelper = new CompatibilityBuildHelper(build);
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setDevice(ITestDevice device) {
+ super.setDevice(device);
+ mDevice = device;
+ }
@Override
protected void setUp() throws Exception {
super.setUp();
- mDevice = getDevice();
-
- /* retrieve the sepolicy-analyze executable from jar */
- sepolicyAnalyze = copyResourceToTempFile("/sepolicy-analyze");
+ sepolicyAnalyze = new File(mHelper.getTestsDir(), "sepolicy-analyze");
sepolicyAnalyze.setExecutable(true);
/* obtain sepolicy file from running device */