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 */