Merge "Additional failure tests for KeyChain" into mnc-dev
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index 3fc5086..c189c12 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -73,6 +73,7 @@
     CtsCertInstallerApp \
     CtsDeviceAdmin \
     CtsDeviceOpenGl \
+    CtsWifiConfigCreator \
     CtsDeviceOwnerApp \
     CtsDeviceTaskswitchingAppA \
     CtsDeviceTaskswitchingAppB \
diff --git a/apps/CameraITS/pymodules/its/image.py b/apps/CameraITS/pymodules/its/image.py
index 8e76c6f..4769bb7 100644
--- a/apps/CameraITS/pymodules/its/image.py
+++ b/apps/CameraITS/pymodules/its/image.py
@@ -211,6 +211,9 @@
     if cap["format"] == "raw10":
         assert(props is not None)
         cap = unpack_raw10_capture(cap, props)
+    if cap["format"] == "raw12":
+        assert(props is not None)
+        cap = unpack_raw12_capture(cap, props)
     if cap["format"] == "yuv":
         y = cap["data"][0:w*h]
         u = cap["data"][w*h:w*h*5/4]
@@ -229,6 +232,36 @@
         img = numpy.ndarray(shape=(h*w,), dtype='<u2',
                             buffer=cap["data"][0:w*h*2])
         img = img.astype(numpy.float32).reshape(h,w) / white_level
+        # Crop the raw image to the active array region.
+        if props.has_key("android.sensor.info.activeArraySize") \
+                and props["android.sensor.info.activeArraySize"] is not None \
+                and props.has_key("android.sensor.info.pixelArraySize") \
+                and props["android.sensor.info.pixelArraySize"] is not None:
+            # Note that the Rect class is defined such that the left,top values
+            # are "inside" while the right,bottom values are "outside"; that is,
+            # it's inclusive of the top,left sides only. So, the width is
+            # computed as right-left, rather than right-left+1, etc.
+            wfull = props["android.sensor.info.pixelArraySize"]["width"]
+            hfull = props["android.sensor.info.pixelArraySize"]["height"]
+            xcrop = props["android.sensor.info.activeArraySize"]["left"]
+            ycrop = props["android.sensor.info.activeArraySize"]["top"]
+            wcrop = props["android.sensor.info.activeArraySize"]["right"]-xcrop
+            hcrop = props["android.sensor.info.activeArraySize"]["bottom"]-ycrop
+            assert(wfull >= wcrop >= 0)
+            assert(hfull >= hcrop >= 0)
+            assert(wfull - wcrop >= xcrop >= 0)
+            assert(hfull - hcrop >= ycrop >= 0)
+            if w == wfull and h == hfull:
+                # Crop needed; extract the center region.
+                img = img[ycrop:ycrop+hcrop,xcrop:xcrop+wcrop]
+                w = wcrop
+                h = hcrop
+            elif w == wcrop and h == hcrop:
+                # No crop needed; image is already cropped to the active array.
+                None
+            else:
+                raise its.error.Error('Invalid image size metadata')
+        # Separate the image planes.
         imgs = [img[::2].reshape(w*h/2)[::2].reshape(h/2,w/2,1),
                 img[::2].reshape(w*h/2)[1::2].reshape(h/2,w/2,1),
                 img[1::2].reshape(w*h/2)[::2].reshape(h/2,w/2,1),
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index 142172b..dd85a19 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -34,8 +34,10 @@
                                androidplot \
                                ctsverifier-opencv \
                                core-tests \
+                               android-support-v4  \
                                mockito-target \
                                mockwebserver \
+                               compatibility-device-util_v2 \
 
 LOCAL_PACKAGE_NAME := CtsVerifier
 
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 070c174..0f4cb6b 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1200,6 +1200,23 @@
                        android:value="android.hardware.type.television:android.software.leanback" />
         </activity>
 -->
+          <activity
+                android:name="com.android.cts.verifier.sensors.DeviceSuspendTestActivity"
+                android:label="@string/snsr_device_suspend_test"
+                android:screenOrientation="nosensor" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_sensors" />
+        </activity>
+
+        <receiver android:name="com.android.cts.verifier.sensors.DeviceSuspendTestActivity$AlarmReceiver">
+        </receiver>
+
+        <receiver android:name="com.android.cts.verifier.sensors.SignificantMotionTestActivity$AlarmReceiver">
+        </receiver>
+
         <activity
             android:name="com.android.cts.verifier.sensors.SignificantMotionTestActivity"
             android:label="@string/snsr_significant_motion_test"
@@ -1300,16 +1317,36 @@
                  android:label="@string/projection_service_name"
                  android:process=":projectionservice" />
 
-        <activity android:name=".managedprovisioning.DeviceOwnerTestActivity"
+        <activity android:name=".managedprovisioning.DeviceOwnerNegativeTestActivity"
                 android:label="@string/provisioning_device_owner">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_managed_provisioning" />
-            <meta-data android:name="test_required_features" android:value="android.software.managed_users:android.software.device_admin" />
+            <meta-data android:name="test_required_features" android:value="android.software.device_admin" />
         </activity>
 
+        <activity android:name=".managedprovisioning.DeviceOwnerPositiveTestActivity"
+                android:label="@string/positive_device_owner">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_managed_provisioning" />
+            <meta-data android:name="test_required_features" android:value="android.software.device_admin" />
+        </activity>
+
+        <activity android:name=".managedprovisioning.DeviceOwnerPositiveTestActivity$CommandReceiver"
+                android:exported="false"
+                android:theme="@android:style/Theme.NoDisplay"
+                android:noHistory="true"
+                android:autoRemoveFromRecents="true"
+                android:stateNotNeeded="true"/>
+
+        <activity android:name=".managedprovisioning.WifiLockdownTestActivity"
+                android:label="@string/device_owner_wifi_lockdown_test">
+        </activity>
 
         <activity android:name=".managedprovisioning.ByodFlowTestActivity"
                 android:launchMode="singleTask"
@@ -1380,7 +1417,7 @@
         </activity>
 
         <receiver android:name=".managedprovisioning.DeviceAdminTestReceiver"
-                android:label="@string/provisioning_byod_device_admin"
+                android:label="@string/afw_device_admin"
                 android:permission="android.permission.BIND_DEVICE_ADMIN">
             <meta-data android:name="android.app.device_admin"
                        android:resource="@xml/device_admin_byod" />
diff --git a/apps/CtsVerifier/res/layout/positive_device_owner.xml b/apps/CtsVerifier/res/layout/positive_device_owner.xml
new file mode 100644
index 0000000..f5d10e0
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/positive_device_owner.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        >
+
+    <ScrollView
+            android:layout_width="match_parent"
+            android:layout_height="320dp"
+            android:layout_weight="2">
+        <TextView
+                android:id="@+id/positive_device_owner_instructions"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:padding="10dip"
+                android:text="@string/device_owner_positive_tests_instructions"
+                android:textSize="18dip" />
+    </ScrollView>
+
+    <Button
+        android:id="@+id/set_device_owner_button"
+        android:layout_width="204dp"
+        android:layout_height="wrap_content"
+        android:text="@string/set_device_owner_button_label" />
+
+    <ListView
+        android:id="@+id/android:list"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="3" />
+
+    <include layout="@layout/pass_fail_buttons" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/wifi_lockdown.xml b/apps/CtsVerifier/res/layout/wifi_lockdown.xml
new file mode 100644
index 0000000..ae6ea0c
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/wifi_lockdown.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        >
+
+    <ScrollView
+            android:layout_width="match_parent"
+            android:layout_height="320dp"
+            android:layout_weight="2">
+        <TextView
+                android:id="@+id/device_owner_wifi_lockdown_info"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:padding="10dip"
+                android:text="@string/device_owner_wifi_lockdown_info"
+                android:textSize="18dip" />
+    </ScrollView>
+
+    <EditText
+        android:id="@+id/device_owner_wifi_ssid"
+        android:hint="(SSID)"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <RadioGroup
+        android:id="@+id/device_owner_keyManagementMethods"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <RadioButton
+            android:id="@+id/device_owner_keymgmnt_none"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/device_owner_wifi_key_management_none_button" />
+        <RadioButton
+            android:id="@+id/device_owner_keymgmnt_wpa"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/device_owner_wifi_key_management_wpa_button" />
+        <RadioButton
+            android:id="@+id/device_owner_keymgmnt_wep"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/device_owner_wifi_key_management_wep_button" />
+    </RadioGroup>
+
+    <Button
+        android:id="@+id/create_wifi_config_button"
+        android:layout_width="204dp"
+        android:layout_height="wrap_content"
+        android:text="@string/create_wifi_config_button_label" />
+
+    <ListView
+        android:id="@+id/android:list"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="3" />
+
+    <include layout="@layout/pass_fail_buttons" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 772fc96..800deb6 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -649,6 +649,14 @@
     <string name="snsr_step_counter_event">%1$d | Step Counter event. count=%2$d.</string>
     <string name="snsr_step_detector_event">%1$d | Step Detector event.</string>
 
+    <!-- Device suspend tests -->
+    <string name="snsr_device_suspend_test">Device Suspend Tests</string>
+    <string name="snsr_device_did_not_go_into_suspend">Device did not go into suspend mode during test execution </string>
+    <string name="snsr_batch_did_not_arrive_at_expected_time">Batch did not arrive at the expected time estimatedBatchArrivalMs=%1$d
+    firstEventReceivedMs=%2$d diffMs=%3$d toleranceMs=%4$d </string>
+    <string name="snsr_device_suspend_test_instr">One you begin the test, disconnect USB, turn off the display and allow
+    the device to go into suspend mode. The screen will turn on and a sound will be played once all the tests are completed.</string>
+
     <!-- Significant Motion -->
     <string name="snsr_significant_motion_test">Significant Motion Tests</string>
     <string name="snsr_significant_motion_event_arrival">Event expected to trigger. Triggered=%1$s.</string>
@@ -663,6 +671,9 @@
     <string name="snsr_significant_motion_test_deactivation">Once you begin the test, you will need to walk to ensure Significant Motion triggers only once.</string>
     <string name="snsr_significant_motion_registration">Expected to be able to register for TriggerSensor. Found=%1$b.</string>
     <string name="snsr_significant_motion_cancelation">Expected to be able to cancel TriggerSensor. Found=%b.</string>
+    <string name="snsr_significant_motion_ap_suspend">One you begin the test, disconnect USB, turn off the display and allow the device to go into suspend.
+    You will need to walk to ensure that Significant Motion triggers. The screen will turn on and a sound will be played once the test completes.</string>
+    <string name="snsr_device_did_not_wake_up_at_trigger">Device did not wakeup at tigger time. wakeTime=%1$d ms triggerTime=%2$d ms</string>
 
     <!-- Strings for Sensor CTS tests inside CtsVerifier -->
     <string name="snsr_single_sensor_tests">CTS Single Sensor Tests</string>
@@ -1366,9 +1377,11 @@
     <string name="snsr_rotation_vector_set_final">Place the device back to the reference position.</string>
     <string name="snsr_rotation_vector_verification">Angular deviation [%1$4.1f %2$4.1f %3$4.1f]. Current: %4$f deg. Max tolerated: %5$f.</string>
 
+    <!-- Strings common for BYOD and DO managed provisioning tests. -->
+    <string name="afw_device_admin">CTS Verifier - AfW Admin</string>
+
     <!-- Strings for BYOD managed provisioning tests (ByodFlowTestActivity) -->
     <string name="test_category_managed_provisioning">Managed Provisioning</string>
-    <string name="provisioning_byod_device_admin">CTS Verifier - BYOD Admin</string>
     <string name="provisioning_byod">BYOD Managed Provisioning</string>
     <string name="provisioning_byod_info">
         This test exercises the BYOD managed provisioning flow.
@@ -1454,7 +1467,7 @@
         Navigate to Device administrators and confirm that:\n
         \n
         - Both Personal and Work categories exist.\n
-        - \"CTS Verifier - BYOD Admin\" exists under the Work category, and is activated.\n
+        - \"CTS Verifier - AfW Admin\" exists under the Work category, and is activated.\n
         \n
         Use the Back button to return to this page.
     </string>
@@ -1525,6 +1538,104 @@
     <string name="device_owner_negative_test">Device owner negative test</string>
     <string name="device_owner_negative_test_info">Please click the "Start provisioning" button, and when you see a warning dialog telling the device is already set up, select "pass". Otherwise, select "fail".</string>
     <string name="start_device_owner_provisioning_button">Start provisioning</string>
+    <string name="positive_device_owner">Device Owner Tests</string>
+    <string name="device_owner_positive_tests">Device Owner positive tests</string>
+    <string name="device_owner_positive_tests_instructions">
+            The positive device owner tests verify policies on a corporate owned device.\n
+            Press below button first, follow steps described in the dialog that pops up,
+            then proceed to the test cases.\n
+            Pressing \'back\', \'pass\' or \'fail\' on this test page will remove the device owner.\n
+            Alternatively, you can run the \'Remove device owner\' test. Ideally, that test should
+            be run last so that it does not interfere with other tests.
+    </string>
+    <string name="device_owner_positive_tests_info">
+            The positive device owner tests verify policies on a corporate owned device.\n
+            Press below button first, follow steps described in the dialog that pops up,
+            then proceed to the test cases.\n
+            Pressing \'back\', \'pass\' or \'fail\' on this test page will remove the device owner.\n
+            Alternatively, you can run the \'Remove device owner\' test. Ideally, that test should
+            be run last so that it does not interfere with other tests.
+    </string>
+    <string name="device_owner_positive_category">Device Owner Tests</string>
+    <string name="set_device_owner_button_label">Set up device owner</string>
+    <string name="set_device_owner_dialog_title">Set up device owner</string>
+    <string name="set_device_owner_dialog_text">
+            Please set the device owner by enabling USB debugging on the device and issuing the following command on the host:\n
+            adb shell dpm set-device-owner \'com.android.cts.verifier/com.android.cts.verifier.managedprovisioning.DeviceAdminTestReceiver\'
+    </string>
+    <string name="device_owner_remove_device_owner_test">Remove device owner</string>
+    <string name="device_owner_remove_device_owner_test_info">
+            Please check in Settings &gt; Security &gt; Device Administrators if CTSVerifier is
+            Device Owner. Then press the button below, and check that CTSVerifier is NOT Device
+            Owner anymore.
+    </string>
+    <string name="remove_device_owner_button">Remove device owner</string>
+    <string name="device_owner_check_device_owner_test">Check device owner</string>
+    <string name="device_owner_incorrect_device_owner">Missing or incorrect device owner: CTSVerifier is not DO!</string>
+    <string name="device_owner_wifi_lockdown_test">WiFi configuration lockdown</string>
+    <string name="device_owner_wifi_lockdown_info">
+            Please enter the SSID and auth method of an available WiFi Access Point and press the button to create a
+            WiFi configuration. This configuration can be seen on Settings &gt; WiFi. The test cases
+            are going use this config. Please go through test cases in order (from top to bottom).
+    </string>
+    <string name="switch_wifi_lockdown_off_button">WiFi config lockdown off</string>
+    <string name="switch_wifi_lockdown_on_button">WiFi config lockdown on</string>
+    <string name="wifi_lockdown_go_settings_wifi_button">Go to WiFi Settings</string>
+    <string name="device_owner_wifi_key_management_none_button">None</string>
+    <string name="device_owner_wifi_key_management_wpa_button">WPA</string>
+    <string name="device_owner_wifi_key_management_wep_button">WEP</string>
+    <string name="create_wifi_config_button_label">Create WiFi configuration</string>
+    <string name="wifi_lockdown_add_network_failed_dialog_title">WiFi configuration could not be created</string>
+    <string name="wifi_lockdown_add_network_failed_dialog_text">
+            There was an error during creation of WiFi configuration. Check if WiFi is switched on.
+    </string>
+    <string name="device_owner_wifi_config_unlocked_modification_test">Unlocked config is modifiable in Settings</string>
+    <string name="device_owner_wifi_config_unlocked_modification_test_info">
+            Please press the button to ensure WiFi config lockdown is NOT in effect. Then go to
+            Settings &gt; WiFi and see if the CTSVerifier created WiFi configuration can be edited.
+            Please make sure you can connect to it. The test is successful if the config is editable
+            and can be connected to.
+    </string>
+    <string name="device_owner_wifi_config_locked_modification_test">Locked config is not modifiable in Settings</string>
+    <string name="device_owner_wifi_config_locked_modification_test_info">
+            Please press the button to ensure WiFi config lockdown is in effect. Then go to
+            Settings &gt; WiFi and see if the CTSVerifier created WiFi configuration can NOT be edited
+            or removed. The test is successful if the config is NOT modifiable.
+    </string>
+    <string name="device_owner_wifi_config_locked_connection_test">Locked config can be connected to</string>
+    <string name="device_owner_wifi_config_locked_connection_test_info">
+            Please press the button to ensure WiFi config lockdown is in effect. Then go to
+            Settings &gt; WiFi and see if the CTSVerifier created WiFi configuration can be connected
+            to manually. The test is successful if the connection can be established.
+    </string>
+    <string name="device_owner_wifi_config_unlocked_removal_test">Unlocked config can be forgotten in Settings</string>
+    <string name="device_owner_wifi_config_unlocked_removal_test_info">
+            Please press the button to ensure WiFi config lockdown is NOT in effect. Then go to
+            Settings &gt; WiFi and see if the CTSVerifier created WiFi configuration can be forgotten.
+            The test is successful if the config could be forgotten and is removed from the list of saved configs.
+    </string>
+    <string name="device_owner_disable_statusbar_test">Disable status bar</string>
+    <string name="device_owner_disable_statusbar_test_info">
+            Please press the below button to disable the status bar and verify that quick settings, notifications
+            and the assist gesture are no longer available.\n
+            Next, press the button to reenable the status bar and verify that quick settings, notification
+            and the assist gesture are available again.\n
+            Please mark the test accordingly.
+    </string>
+    <string name="device_owner_disable_statusbar_button">Disable status bar</string>
+    <string name="device_owner_reenable_statusbar_button">Reenable status bar</string>
+    <string name="device_owner_disable_keyguard_test">Disable keyguard</string>
+    <string name="device_owner_disable_keyguard_test_info">
+            Note that any device passwords that you might have set will be deleted during this test.\n
+            Please press the below button to disable the keyguard. Press the power button on your device to
+            switch off the screen. Then press the power button to switch the screen back on and verify that
+            no keyguard was shown.\n
+            Next, press the button to reenable the keyguard and repeat the above steps, this time verifying that
+            a keyguard was shown again.\n
+            Please mark the test accordingly.
+    </string>
+    <string name="device_owner_disable_keyguard_button">Disable keyguard</string>
+    <string name="device_owner_reenable_keyguard_button">Reenable keyguard</string>
 
     <!-- Strings for JobScheduler Tests -->
     <string name="js_test_description">This test is mostly automated, but requires some user interaction. You can pass this test once the list items below are checked.</string>
diff --git a/apps/CtsVerifier/res/xml/device_admin_byod.xml b/apps/CtsVerifier/res/xml/device_admin_byod.xml
index 0408ce2..61238aa 100644
--- a/apps/CtsVerifier/res/xml/device_admin_byod.xml
+++ b/apps/CtsVerifier/res/xml/device_admin_byod.xml
@@ -19,6 +19,7 @@
     <uses-policies>
         <encrypted-storage />
         <wipe-data />
+        <reset-password />
     </uses-policies>
 </device-admin>
 <!-- END_INCLUDE(meta_data) -->
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
index 9154307..ef5d62d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
@@ -22,9 +22,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.PackageManager;
 import android.util.Log;
-import android.widget.Toast;
 
 /**
  * Profile owner receiver for BYOD flow test.
@@ -32,6 +30,16 @@
  */
 public class DeviceAdminTestReceiver extends DeviceAdminReceiver {
         private static final String TAG = "DeviceAdminTestReceiver";
+        private static final String DEVICE_OWNER_PKG =
+                "com.android.cts.verifier";
+        private static final String ADMIN_RECEIVER_TEST_CLASS =
+                DEVICE_OWNER_PKG + ".managedprovisioning.DeviceAdminTestReceiver";
+        private static final ComponentName RECEIVER_COMPONENT_NAME = new ComponentName(
+                DEVICE_OWNER_PKG, ADMIN_RECEIVER_TEST_CLASS);
+
+        public static ComponentName getReceiverComponentName() {
+            return RECEIVER_COMPONENT_NAME;
+        }
 
         @Override
         public void onProfileProvisioningComplete(Context context, Intent intent) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerNegativeTestActivity.java
similarity index 80%
rename from apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerTestActivity.java
rename to apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerNegativeTestActivity.java
index 7cb3825..c7e785c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerNegativeTestActivity.java
@@ -1,22 +1,24 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package com.android.cts.verifier.managedprovisioning;
 
-import android.app.AlertDialog;
-import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.DialogInterface;
 import android.content.Intent;
 import android.database.DataSetObserver;
 import android.os.Bundle;
-import android.provider.Settings;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.View.OnClickListener;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.widget.Toast;
 
 import com.android.cts.verifier.ArrayTestListAdapter;
 import com.android.cts.verifier.IntentDrivenTestActivity;
@@ -26,13 +28,10 @@
 import com.android.cts.verifier.R;
 import com.android.cts.verifier.TestListAdapter.TestListItem;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
- * Activity that lists all device owner provisioning tests.
+ * Activity that lists all device owner negative tests.
  */
-public class DeviceOwnerTestActivity extends PassFailButtons.TestListActivity {
+public class DeviceOwnerNegativeTestActivity extends PassFailButtons.TestListActivity {
 
     private static final String ACTION_PROVISION_MANAGED_DEVICE
         = "com.android.managedprovisioning.ACTION_PROVISION_MANAGED_DEVICE";
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
new file mode 100644
index 0000000..1a5e73c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.managedprovisioning;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.database.DataSetObserver;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import com.android.cts.verifier.ArrayTestListAdapter;
+import com.android.cts.verifier.IntentDrivenTestActivity;
+import com.android.cts.verifier.IntentDrivenTestActivity.ButtonInfo;
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.TestListAdapter.TestListItem;
+import com.android.cts.verifier.TestResult;
+
+/**
+ * Activity that lists all positive device owner tests. Requires the following adb command be issued
+ * by the user prior to starting the tests:
+ *
+ * adb shell dpm set-device-owner
+ *  'com.android.cts.verifier/com.android.cts.verifier.managedprovisioning.DeviceAdminTestReceiver'
+ */
+public class DeviceOwnerPositiveTestActivity extends PassFailButtons.TestListActivity {
+    private static final String TAG = "DeviceOwnerPositiveTestActivity";
+
+    static final String EXTRA_COMMAND = "extra-command";
+    static final String EXTRA_TEST_ID = "extra-test-id";
+    static final String COMMAND_SET_POLICY = "set-policy";
+    static final String EXTRA_POLICY = "extra-policy";
+    static final String EXTRA_PARAMETER_1 = "extra_parameter_1";
+    static final String EXTRA_PARAMETER_2 = "extra_parameter_2";
+    static final String COMMAND_ADD_USER_RESTRICTION = "add-user-restriction";
+    static final String COMMAND_CLEAR_USER_RESTRICTION = "clear-user-restriction";
+    static final String EXTRA_RESTRICTION = "extra-restriction";
+    static final String COMMAND_TEAR_DOWN = "tear-down";
+    static final String COMMAND_CHECK_DEVICE_OWNER = "check-device-owner";
+    static final String COMMAND_SET_GLOBAL_SETTING = "set-global-setting";
+    static final String COMMAND_SET_STATUSBAR_DISABLED = "set-statusbar-disabled";
+    static final String COMMAND_SET_KEYGUARD_DISABLED = "set-keyguard-disabled";
+    static final String EXTRA_SETTING = "extra-setting";
+
+    private static final String CHECK_DEVICE_OWNER_TEST_ID = "CHECK_DEVICE_OWNER";
+    private static final String WIFI_LOCKDOWN_TEST_ID = WifiLockdownTestActivity.class.getName();
+    private static final String DISABLE_STATUS_BAR_TEST_ID = "DISABLE_STATUS_BAR";
+    private static final String DISABLE_KEYGUARD_TEST_ID = "DISABLE_KEYGUARD";
+    private static final String REMOVE_DEVICE_OWNER_TEST_ID = "REMOVE_DEVICE_OWNER";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.positive_device_owner);
+        setInfoResources(R.string.device_owner_positive_tests,
+                R.string.device_owner_positive_tests_info, 0);
+        setPassFailButtonClickListeners();
+
+        final ArrayTestListAdapter adapter = new ArrayTestListAdapter(this);
+        adapter.add(TestListItem.newCategory(this, R.string.device_owner_positive_category));
+
+        addTestsToAdapter(adapter);
+
+        adapter.registerDataSetObserver(new DataSetObserver() {
+            @Override
+            public void onChanged() {
+                updatePassButton();
+            }
+        });
+
+        setTestListAdapter(adapter);
+
+        View setDeviceOwnerButton = findViewById(R.id.set_device_owner_button);
+        setDeviceOwnerButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                new AlertDialog.Builder(
+                        DeviceOwnerPositiveTestActivity.this)
+                        .setIcon(android.R.drawable.ic_dialog_info)
+                        .setTitle(R.string.set_device_owner_dialog_title)
+                        .setMessage(R.string.set_device_owner_dialog_text)
+                        .setPositiveButton(android.R.string.ok, null)
+                        .show();
+            }
+        });
+
+    }
+
+    @Override
+    public void finish() {
+        // Pass and fail buttons are known to call finish() when clicked, and this is when we want
+        // to remove the device owner.
+        startActivity(createTearDownIntent());
+        super.finish();
+    }
+
+    /**
+     * Enable Pass Button when all tests passed.
+     */
+    private void updatePassButton() {
+        getPassButton().setEnabled(mAdapter.allTestsPassed());
+    }
+
+    private void addTestsToAdapter(final ArrayTestListAdapter adapter) {
+        adapter.add(createTestItem(this, CHECK_DEVICE_OWNER_TEST_ID,
+                R.string.device_owner_check_device_owner_test,
+                new Intent(this, CommandReceiver.class)
+                        .putExtra(EXTRA_COMMAND, COMMAND_CHECK_DEVICE_OWNER)
+                        ));
+        PackageManager packageManager = getPackageManager();
+        if (packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
+            adapter.add(createTestItem(this, WIFI_LOCKDOWN_TEST_ID,
+                    R.string.device_owner_wifi_lockdown_test,
+                    new Intent(this, WifiLockdownTestActivity.class)));
+        }
+
+        // setStatusBarDisabled
+        adapter.add(createInteractiveTestItem(this, DISABLE_STATUS_BAR_TEST_ID,
+                R.string.device_owner_disable_statusbar_test,
+                R.string.device_owner_disable_statusbar_test_info,
+                new ButtonInfo[] {
+                        new ButtonInfo(
+                                R.string.device_owner_disable_statusbar_button,
+                                createDeviceOwnerIntentWithBooleanParameter(
+                                        COMMAND_SET_STATUSBAR_DISABLED, true)),
+                        new ButtonInfo(
+                                R.string.device_owner_reenable_statusbar_button,
+                                createDeviceOwnerIntentWithBooleanParameter(
+                                        COMMAND_SET_STATUSBAR_DISABLED, false))}));
+
+        // setKeyguardDisabled
+        adapter.add(createInteractiveTestItem(this, DISABLE_KEYGUARD_TEST_ID,
+                R.string.device_owner_disable_keyguard_test,
+                R.string.device_owner_disable_keyguard_test_info,
+                new ButtonInfo[] {
+                        new ButtonInfo(
+                                R.string.device_owner_disable_keyguard_button,
+                                createDeviceOwnerIntentWithBooleanParameter(
+                                        COMMAND_SET_KEYGUARD_DISABLED, true)),
+                        new ButtonInfo(
+                                R.string.device_owner_reenable_keyguard_button,
+                                createDeviceOwnerIntentWithBooleanParameter(
+                                        COMMAND_SET_KEYGUARD_DISABLED, false))}));
+
+        // removeDeviceOwner
+        adapter.add(createInteractiveTestItem(this, REMOVE_DEVICE_OWNER_TEST_ID,
+                R.string.device_owner_remove_device_owner_test,
+                R.string.device_owner_remove_device_owner_test_info,
+                new ButtonInfo(
+                        R.string.remove_device_owner_button,
+                        createTearDownIntent())));
+    }
+
+    static TestListItem createInteractiveTestItem(Activity activity, String id, int titleRes,
+            int infoRes, ButtonInfo buttonInfo) {
+        return createInteractiveTestItem(activity, id, titleRes, infoRes,
+                new ButtonInfo[] { buttonInfo });
+    }
+
+    static TestListItem createInteractiveTestItem(Activity activity, String id, int titleRes,
+            int infoRes, ButtonInfo[] buttonInfos) {
+        return TestListItem.newTest(activity, titleRes,
+                id, new Intent(activity, IntentDrivenTestActivity.class)
+                .putExtra(IntentDrivenTestActivity.EXTRA_ID, id)
+                .putExtra(IntentDrivenTestActivity.EXTRA_TITLE, titleRes)
+                .putExtra(IntentDrivenTestActivity.EXTRA_INFO, infoRes)
+                .putExtra(IntentDrivenTestActivity.EXTRA_BUTTONS, buttonInfos),
+                null);
+    }
+
+    static TestListItem createTestItem(Activity activity, String id, int titleRes,
+            Intent intent) {
+        return TestListItem.newTest(activity, titleRes, id, intent.putExtra(EXTRA_TEST_ID, id),
+                null);
+    }
+
+    private Intent createTearDownIntent() {
+        return new Intent(this, CommandReceiver.class)
+                .putExtra(EXTRA_COMMAND, COMMAND_TEAR_DOWN);
+    }
+
+    private Intent createDeviceOwnerIntentWithBooleanParameter(String command, boolean value) {
+        return new Intent(this, CommandReceiver.class)
+                .putExtra(EXTRA_COMMAND, command)
+                .putExtra(EXTRA_PARAMETER_1, value);
+    }
+
+    public static class CommandReceiver extends Activity {
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            Intent intent = getIntent();
+            String command = intent.getStringExtra(EXTRA_COMMAND);
+            try {
+                DevicePolicyManager dpm = (DevicePolicyManager)
+                        getSystemService(Context.DEVICE_POLICY_SERVICE);
+                ComponentName admin = DeviceAdminTestReceiver.getReceiverComponentName();
+                Log.i(TAG, "Command: " + command);
+
+                if (COMMAND_ADD_USER_RESTRICTION.equals(command)) {
+                    String restrictionKey = intent.getStringExtra(EXTRA_RESTRICTION);
+                    dpm.addUserRestriction(admin, restrictionKey);
+                    Log.i(TAG, "Added user restriction " + restrictionKey);
+                } else if (COMMAND_CLEAR_USER_RESTRICTION.equals(command)) {
+                    String restrictionKey = intent.getStringExtra(EXTRA_RESTRICTION);
+                    dpm.clearUserRestriction(admin, restrictionKey);
+                    Log.i(TAG, "Cleared user restriction " + restrictionKey);
+                } else if (COMMAND_TEAR_DOWN.equals(command)) {
+                    tearDown(dpm, admin);
+                } else if (COMMAND_SET_GLOBAL_SETTING.equals(command)) {
+                    final String setting = intent.getStringExtra(EXTRA_SETTING);
+                    final String value = intent.getStringExtra(EXTRA_PARAMETER_1);
+                    dpm.setGlobalSetting(admin, setting, value);
+                } else if (COMMAND_SET_STATUSBAR_DISABLED.equals(command)) {
+                    final boolean value = intent.getBooleanExtra(EXTRA_PARAMETER_1, false);
+                    dpm.setStatusBarDisabled(admin, value);
+                } else if (COMMAND_SET_KEYGUARD_DISABLED.equals(command)) {
+                    final boolean value = intent.getBooleanExtra(EXTRA_PARAMETER_1, false);
+                    if (value) {
+                        dpm.resetPassword(null, 0);
+                    }
+                    dpm.setKeyguardDisabled(admin, value);
+                } else if (COMMAND_CHECK_DEVICE_OWNER.equals(command)) {
+                    if (dpm.isDeviceOwnerApp(getPackageName())) {
+                        TestResult.setPassedResult(this, intent.getStringExtra(EXTRA_TEST_ID),
+                                null, null);
+                    } else {
+                        TestResult.setFailedResult(this, intent.getStringExtra(EXTRA_TEST_ID),
+                                getString(R.string.device_owner_incorrect_device_owner), null);
+                    }
+                } else {
+                    Log.e(TAG, "Invalid command: " + command);
+                }
+            } catch (Exception e) {
+                Log.e(TAG, "Command " + command + " failed with exception " + e);
+            } finally {
+                // No matter what happened, don't let the activity run
+                finish();
+            }
+        }
+
+        private void tearDown(DevicePolicyManager dpm, ComponentName admin) {
+            if (dpm == null || !dpm.isDeviceOwnerApp(getPackageName())) {
+                return;
+            }
+
+            dpm.setStatusBarDisabled(admin, false);
+            dpm.setKeyguardDisabled(admin, false);
+            dpm.clearDeviceOwnerApp(getPackageName());
+        }
+    }
+}
+
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WifiLockdownTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WifiLockdownTestActivity.java
new file mode 100644
index 0000000..4a292eb
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WifiLockdownTestActivity.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.managedprovisioning;
+
+import android.app.AlertDialog;
+import android.content.Intent;
+import android.database.DataSetObserver;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.EditText;
+import android.widget.RadioGroup;
+
+import com.android.cts.verifier.ArrayTestListAdapter;
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.IntentDrivenTestActivity.ButtonInfo;
+
+import com.android.compatibility.common.util.WifiConfigCreator;
+import static com.android.compatibility.common.util.WifiConfigCreator.SECURITY_TYPE_NONE;
+import static com.android.compatibility.common.util.WifiConfigCreator.SECURITY_TYPE_WPA;
+import static com.android.compatibility.common.util.WifiConfigCreator.SECURITY_TYPE_WEP;
+
+/**
+ * Activity to test WiFi configuration lockdown functionality. A locked down WiFi config
+ * must not be editable/forgettable in Settings.
+ */
+public class WifiLockdownTestActivity extends PassFailButtons.TestListActivity {
+    private static final String TAG = "WifiLockdownTestActivity";
+
+    private static final int NONE = R.id.device_owner_keymgmnt_none;
+    private static final int WPA = R.id.device_owner_keymgmnt_wpa;
+    private static final int WEP = R.id.device_owner_keymgmnt_wep;
+
+    private static final String CONFIG_MODIFIABLE_WHEN_UNLOCKED_TEST_ID = "UNLOCKED_MODIFICATION";
+    private static final String CONFIG_NOT_MODIFIABLE_WHEN_LOCKED_TEST_ID = "LOCKED_MODIFICATION";
+    private static final String CONFIG_CONNECTABLE_WHEN_LOCKED_TEST_ID = "LOCKED_CONNECT";
+    private static final String CONFIG_REMOVABLE_WHEN_UNLOCKED_TEST_ID = "UNLOCKED_REMOVE";
+
+    private WifiConfigCreator mConfigCreator;
+    private ButtonInfo[] mSwitchLockdownOffButtonInfos;
+    private ButtonInfo[] mSwitchLockdownOnButtonInfos;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mConfigCreator = new WifiConfigCreator(this);
+        setContentView(R.layout.wifi_lockdown);
+        setInfoResources(R.string.device_owner_wifi_lockdown_test,
+                R.string.device_owner_wifi_lockdown_info, 0);
+        setPassFailButtonClickListeners();
+
+        final ArrayTestListAdapter adapter = new ArrayTestListAdapter(this);
+
+        final ButtonInfo goToWifiSettings = new ButtonInfo(
+                R.string.wifi_lockdown_go_settings_wifi_button,
+                new Intent(Settings.ACTION_WIFI_SETTINGS));
+        mSwitchLockdownOffButtonInfos = new ButtonInfo[] { new ButtonInfo(
+                R.string.switch_wifi_lockdown_off_button,
+                new Intent(this, DeviceOwnerPositiveTestActivity.CommandReceiver.class)
+                        .putExtra(DeviceOwnerPositiveTestActivity.EXTRA_COMMAND,
+                                DeviceOwnerPositiveTestActivity.COMMAND_SET_GLOBAL_SETTING)
+                        .putExtra(DeviceOwnerPositiveTestActivity.EXTRA_SETTING,
+                                Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN)
+                        .putExtra(DeviceOwnerPositiveTestActivity.EXTRA_PARAMETER_1, "0"
+                )), goToWifiSettings };
+        mSwitchLockdownOnButtonInfos = new ButtonInfo[] { new ButtonInfo(
+                R.string.switch_wifi_lockdown_on_button,
+                new Intent(this, DeviceOwnerPositiveTestActivity.CommandReceiver.class)
+                        .putExtra(DeviceOwnerPositiveTestActivity.EXTRA_COMMAND,
+                                DeviceOwnerPositiveTestActivity.COMMAND_SET_GLOBAL_SETTING)
+                        .putExtra(DeviceOwnerPositiveTestActivity.EXTRA_SETTING,
+                                Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN)
+                        .putExtra(DeviceOwnerPositiveTestActivity.EXTRA_PARAMETER_1, "1"
+                )), goToWifiSettings };
+
+        addTestsToAdapter(adapter);
+
+        adapter.registerDataSetObserver(new DataSetObserver() {
+            @Override
+            public void onChanged() {
+                updatePassButton();
+            }
+        });
+
+        setTestListAdapter(adapter);
+
+        View createConfigButton = findViewById(R.id.create_wifi_config_button);
+        createConfigButton .setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                EditText ssidEditor = (EditText) findViewById(R.id.device_owner_wifi_ssid);
+                RadioGroup authMethods = (RadioGroup) findViewById(
+                        R.id.device_owner_keyManagementMethods);
+                int checkedRadioId = authMethods.getCheckedRadioButtonId();
+                if (checkedRadioId == -1) {
+                    checkedRadioId = NONE;
+                }
+                int netId = mConfigCreator.addNetwork(ssidEditor.getText().toString(), false,
+                        convertKeyManagement(checkedRadioId), "defaultpassword");
+                if (netId == -1) {
+                    new AlertDialog.Builder(
+                            WifiLockdownTestActivity.this)
+                            .setIcon(android.R.drawable.ic_dialog_info)
+                            .setTitle(R.string.wifi_lockdown_add_network_failed_dialog_title)
+                            .setMessage(R.string.wifi_lockdown_add_network_failed_dialog_text)
+                            .setPositiveButton(android.R.string.ok, null)
+                            .show();
+                }
+            }
+        });
+    }
+
+    /**
+     * Enable Pass Button when all tests passed.
+     */
+    private void updatePassButton() {
+        getPassButton().setEnabled(mAdapter.allTestsPassed());
+    }
+
+    private void addTestsToAdapter(final ArrayTestListAdapter adapter) {
+        adapter.add(DeviceOwnerPositiveTestActivity.createInteractiveTestItem(this,
+                CONFIG_MODIFIABLE_WHEN_UNLOCKED_TEST_ID,
+                R.string.device_owner_wifi_config_unlocked_modification_test,
+                R.string.device_owner_wifi_config_unlocked_modification_test_info,
+                mSwitchLockdownOffButtonInfos));
+        adapter.add(DeviceOwnerPositiveTestActivity.createInteractiveTestItem(this,
+                CONFIG_NOT_MODIFIABLE_WHEN_LOCKED_TEST_ID,
+                R.string.device_owner_wifi_config_locked_modification_test,
+                R.string.device_owner_wifi_config_locked_modification_test_info,
+                mSwitchLockdownOnButtonInfos));
+        adapter.add(DeviceOwnerPositiveTestActivity.createInteractiveTestItem(this,
+                CONFIG_CONNECTABLE_WHEN_LOCKED_TEST_ID,
+                R.string.device_owner_wifi_config_locked_connection_test,
+                R.string.device_owner_wifi_config_locked_connection_test_info,
+                mSwitchLockdownOnButtonInfos));
+        adapter.add(DeviceOwnerPositiveTestActivity.createInteractiveTestItem(this,
+                CONFIG_REMOVABLE_WHEN_UNLOCKED_TEST_ID,
+                R.string.device_owner_wifi_config_unlocked_removal_test,
+                R.string.device_owner_wifi_config_unlocked_removal_test_info,
+                mSwitchLockdownOffButtonInfos));
+    }
+
+    private int convertKeyManagement(int radioButtonId) {
+        switch (radioButtonId) {
+            case NONE: {
+                return SECURITY_TYPE_NONE;
+            }
+            case WPA: {
+                return SECURITY_TYPE_WPA;
+            }
+            case WEP: {
+                return SECURITY_TYPE_WEP;
+            }
+        }
+        return SECURITY_TYPE_NONE;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/DeviceSuspendTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/DeviceSuspendTestActivity.java
new file mode 100644
index 0000000..d066fce
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/DeviceSuspendTestActivity.java
@@ -0,0 +1,263 @@
+package com.android.cts.verifier.sensors;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.sensors.base.SensorCtsVerifierTestActivity;
+import com.android.cts.verifier.sensors.helpers.SensorTestScreenManipulator;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.hardware.TriggerEvent;
+import android.hardware.TriggerEventListener;
+import android.hardware.cts.helpers.MovementDetectorHelper;
+import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.SensorTestStateNotSupportedException;
+import android.hardware.cts.helpers.TestSensorEnvironment;
+import android.hardware.cts.helpers.TestSensorEvent;
+import android.hardware.cts.helpers.TestSensorEventListener;
+import android.hardware.cts.helpers.TestSensorManager;
+import android.hardware.cts.helpers.sensoroperations.TestSensorOperation;
+import android.hardware.cts.helpers.SensorNotSupportedException;
+import android.hardware.cts.helpers.sensorverification.BatchArrivalVerification;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.os.SystemClock;
+import android.support.v4.content.LocalBroadcastManager;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+
+import junit.framework.Assert;
+
+public class DeviceSuspendTestActivity
+            extends SensorCtsVerifierTestActivity {
+        public DeviceSuspendTestActivity() {
+            super(DeviceSuspendTestActivity.class);
+        }
+
+        private SensorTestScreenManipulator mScreenManipulator;
+        private PowerManager.WakeLock mDeviceSuspendLock;
+        private PendingIntent mPendingIntent;
+        private AlarmManager mAlarmManager;
+        private static String ACTION_ALARM = "DeviceSuspendTestActivity.ACTION_ALARM";
+        private static String TAG = "DeviceSuspendTestActivity";
+        private SensorManager mSensorManager;
+
+        @Override
+        protected void activitySetUp() throws InterruptedException {
+            mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
+            mScreenManipulator = new SensorTestScreenManipulator(this);
+            mScreenManipulator.initialize(this);
+            LocalBroadcastManager.getInstance(this).registerReceiver(myBroadCastReceiver,
+                                            new IntentFilter(ACTION_ALARM));
+
+            Intent intent = new Intent(this, AlarmReceiver.class);
+            mPendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
+
+            mAlarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
+
+            PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
+            mDeviceSuspendLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+                                                "DeviceSuspendTestActivity");
+            mDeviceSuspendLock.acquire();
+            SensorTestLogger logger = getTestLogger();
+            logger.logInstructions(R.string.snsr_device_suspend_test_instr);
+            waitForUserToBegin();
+        }
+
+        @Override
+        protected void activityCleanUp() {
+            mScreenManipulator.turnScreenOn();
+            try {
+                playSound();
+            } catch(InterruptedException e) {
+              // Ignore.
+            }
+            LocalBroadcastManager.getInstance(this).unregisterReceiver(myBroadCastReceiver);
+        }
+
+        @Override
+        protected void onDestroy() {
+            super.onDestroy();
+            if (mScreenManipulator != null) {
+                mScreenManipulator.releaseScreenOn();
+                mScreenManipulator.close();
+            }
+            if (mDeviceSuspendLock.isHeld()) {
+                mDeviceSuspendLock.release();
+            }
+        }
+
+        public static class AlarmReceiver extends BroadcastReceiver {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                Intent alarm_intent = new Intent(context, DeviceSuspendTestActivity.class);
+                alarm_intent.setAction(DeviceSuspendTestActivity.ACTION_ALARM);
+                LocalBroadcastManager.getInstance(context).sendBroadcastSync(alarm_intent);
+            }
+        }
+
+        public BroadcastReceiver myBroadCastReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (!mDeviceSuspendLock.isHeld()) {
+                    mDeviceSuspendLock.acquire();
+                }
+            }
+        };
+
+        public String testAPWakeUpWhenReportLatencyExpiresAccel() throws Throwable {
+            Sensor wakeUpSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER, true);
+            if (wakeUpSensor == null) {
+                throw new SensorNotSupportedException(Sensor.TYPE_ACCELEROMETER, true);
+            }
+            return runAPWakeUpWhenReportLatencyExpires(wakeUpSensor);
+        }
+
+        public String testAPWakeUpWhenReportLatencyExpiresGyro() throws Throwable {
+            Sensor wakeUpSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE, true);
+            if (wakeUpSensor == null) {
+                throw new SensorNotSupportedException(Sensor.TYPE_GYROSCOPE, true);
+            }
+            return runAPWakeUpWhenReportLatencyExpires(wakeUpSensor);
+        }
+
+        public String testAPWakeUpWhenReportLatencyExpiresMag() throws Throwable {
+            Sensor wakeUpSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD,true);
+            if (wakeUpSensor == null) {
+                throw new SensorNotSupportedException(Sensor.TYPE_MAGNETIC_FIELD, true);
+            }
+            return runAPWakeUpWhenFIFOFull(wakeUpSensor);
+        }
+
+        public String testAPWakeUpWhenFIFOFullAccel() throws Throwable {
+            Sensor wakeUpSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER, true);
+            if (wakeUpSensor == null) {
+                throw new SensorNotSupportedException(Sensor.TYPE_ACCELEROMETER, true);
+            }
+            return runAPWakeUpWhenFIFOFull(wakeUpSensor);
+        }
+
+        public String testAPWakeUpWhenFIFOFullGyro() throws Throwable {
+            Sensor wakeUpSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE, true);
+            if (wakeUpSensor == null) {
+                throw new SensorNotSupportedException(Sensor.TYPE_GYROSCOPE, true);
+            }
+            return runAPWakeUpWhenFIFOFull(wakeUpSensor);
+        }
+
+        public String testAPWakeUpWhenFIFOFullMag() throws Throwable {
+            Sensor wakeUpSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD,true);
+            if (wakeUpSensor == null) {
+                throw new SensorNotSupportedException(Sensor.TYPE_MAGNETIC_FIELD, true);
+            }
+            return runAPWakeUpWhenFIFOFull(wakeUpSensor);
+        }
+
+        public String runAPWakeUpWhenReportLatencyExpires(Sensor sensor) throws Throwable {
+            int fifoMaxEventCount = sensor.getFifoMaxEventCount();
+            if (fifoMaxEventCount == 0) {
+                throw new SensorTestStateNotSupportedException("Batching not supported.");
+            }
+            int maximumExpectedSamplingPeriodUs = sensor.getMaxDelay();
+            if (maximumExpectedSamplingPeriodUs == 0) {
+                // If maxDelay is not defined, set the value for 5 Hz.
+                maximumExpectedSamplingPeriodUs = 200000;
+            }
+            int fifoBasedReportLatencyUs = fifoMaxEventCount * maximumExpectedSamplingPeriodUs;
+
+            // Ensure that FIFO based report latency is at least 20 seconds, we need at least 10
+            // seconds of time to allow the device to be in suspend state.
+            if (fifoBasedReportLatencyUs < 20000000L) {
+                throw new SensorTestStateNotSupportedException("FIFO too small to test reliably");
+            }
+
+            final int MAX_REPORT_LATENCY_US = 15000000; // 15 seconds
+            TestSensorEnvironment environment = new TestSensorEnvironment(
+                    this,
+                    sensor,
+                    false,
+                    maximumExpectedSamplingPeriodUs,
+                    MAX_REPORT_LATENCY_US,
+                    true /*isDeviceSuspendTest*/);
+
+            int numEventsToWaitFor = MAX_REPORT_LATENCY_US/maximumExpectedSamplingPeriodUs;
+            TestSensorOperation op = TestSensorOperation.createOperation(environment,
+                                                                          numEventsToWaitFor,
+                                                                          mDeviceSuspendLock,
+                                                                          false);
+            final int ALARM_WAKE_UP_DELAY_MS = MAX_REPORT_LATENCY_US/1000 +
+                (int)TimeUnit.SECONDS.toMillis(10);
+            op.addVerification(BatchArrivalVerification.getDefault(environment));
+            mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                                    SystemClock.elapsedRealtime() + ALARM_WAKE_UP_DELAY_MS,
+                                    mPendingIntent);
+            try {
+                op.execute(getCurrentTestNode());
+            } finally {
+                mAlarmManager.cancel(mPendingIntent);
+            }
+            return null;
+        }
+
+        public String runAPWakeUpWhenFIFOFull(Sensor sensor) throws Throwable {
+            int fifoMaxEventCount = sensor.getFifoMaxEventCount();
+            if (fifoMaxEventCount == 0) {
+                throw new SensorTestStateNotSupportedException("Batching not supported.");
+            }
+            // Try to fill the FIFO at the fastest rate and check if the time is enough to run
+            // the manual test.
+            int maximumExpectedSamplingPeriodUs = sensor.getMinDelay();
+            int fifoBasedReportLatencyUs = fifoMaxEventCount * maximumExpectedSamplingPeriodUs;
+
+            final int MIN_LATENCY_US = (int)TimeUnit.SECONDS.toMicros(20);
+            // Ensure that FIFO based report latency is at least 20 seconds, we need at least 10
+            // seconds of time to allow the device to be in suspend state.
+            if (fifoBasedReportLatencyUs < MIN_LATENCY_US) {
+                maximumExpectedSamplingPeriodUs = MIN_LATENCY_US/fifoMaxEventCount;
+                fifoBasedReportLatencyUs = MIN_LATENCY_US;
+            }
+
+            final int MAX_REPORT_LATENCY_US = Integer.MAX_VALUE;
+            final int ALARM_WAKE_UP_DELAY_MS = fifoBasedReportLatencyUs/1000 +
+                (int)TimeUnit.SECONDS.toMillis(10);
+            TestSensorEnvironment environment = new TestSensorEnvironment(
+                    this,
+                    sensor,
+                    false,
+                    maximumExpectedSamplingPeriodUs,
+                    MAX_REPORT_LATENCY_US,
+                    true /*isDeviceSuspendTest*/);
+
+           int numEventsToWaitFor = fifoMaxEventCount;
+            TestSensorOperation op = TestSensorOperation.createOperation(environment,
+                                                                          numEventsToWaitFor,
+                                                                          mDeviceSuspendLock,
+                                                                         true);
+            mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                                    SystemClock.elapsedRealtime() + ALARM_WAKE_UP_DELAY_MS,
+                                    mPendingIntent);
+            op.addDefaultVerifications();
+            try {
+                op.execute(getCurrentTestNode());
+            } finally {
+                mAlarmManager.cancel(mPendingIntent);
+            }
+            return null;
+        }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java
index faba445..f8f1a9a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java
@@ -16,22 +16,36 @@
 
 package com.android.cts.verifier.sensors;
 
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 import com.android.cts.verifier.R;
 import com.android.cts.verifier.sensors.base.SensorCtsVerifierTestActivity;
+import com.android.cts.verifier.sensors.helpers.SensorTestScreenManipulator;
 
-import junit.framework.Assert;
-
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.hardware.Sensor;
 import android.hardware.SensorManager;
 import android.hardware.TriggerEvent;
 import android.hardware.TriggerEventListener;
 import android.hardware.cts.helpers.SensorNotSupportedException;
 import android.hardware.cts.helpers.TestSensorEnvironment;
+import android.hardware.cts.helpers.SuspendStateMonitor;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PowerManager;
 import android.os.SystemClock;
+import android.support.v4.content.LocalBroadcastManager;
+import android.util.Log;
 
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
+import junit.framework.Assert;
 
 /**
  * Test cases for Significant Motion sensor.
@@ -46,20 +60,30 @@
     private static final long MAX_ACCEPTABLE_EVENT_TIME_DELAY_NANOS =
             TimeUnit.MILLISECONDS.toNanos(500);
 
+    // acceptable time difference between event time and AP wake up time.
+    private static final long MAX_ACCEPTABLE_DELAY_EVENT_AP_WAKE_UP_NS =
+            TimeUnit.MILLISECONDS.toNanos(2000);
+
+    // time to wait for SMD after the device has gone into suspend. Even after
+    // 45 secs if SMD does not trigger, the test will fail.
+    private static final long ALARM_WAKE_TIME_DELAY_MS = TimeUnit.SECONDS.toMillis(45);
+
     // time for the test to wait for a trigger
     private static final int TRIGGER_MAX_DELAY_SECONDS = 30;
     private static final int VIBRATE_DURATION_MILLIS = 10000;
 
     private static final int EVENT_VALUES_LENGTH = 1;
     private static final float EXPECTED_EVENT_VALUE = 1.0f;
+    private static String ACTION_ALARM = "SignificantMotionTestActivity.ACTION_ALARM";
 
     private SensorManager mSensorManager;
     private Sensor mSensorSignificantMotion;
+    private TriggerVerifier mVerifier;
+    private SensorTestScreenManipulator mScreenManipulator;
 
     /**
      * Test cases.
      */
-
     @SuppressWarnings("unused")
     public String testTrigger() throws Throwable {
         return runTest(
@@ -131,6 +155,69 @@
         return result;
     }
 
+    public static class AlarmReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Intent alarm_intent = new Intent(context, SignificantMotionTestActivity.class);
+            alarm_intent.setAction(SignificantMotionTestActivity.ACTION_ALARM);
+            LocalBroadcastManager.getInstance(context).sendBroadcastSync(alarm_intent);
+        }
+    }
+
+    public BroadcastReceiver myBroadCastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mVerifier.releaseLatch();
+            mScreenManipulator.turnScreenOn();
+            try {
+                playSound();
+            } catch (InterruptedException e) {
+                // Ignore ...
+            }
+        }
+    };
+
+    @SuppressWarnings("unused")
+    public String testAPWakeUpOnSMDTrigger() throws Throwable {
+        SensorTestLogger logger = getTestLogger();
+        logger.logInstructions(R.string.snsr_significant_motion_ap_suspend);
+        waitForUserToBegin();
+        mVerifier = new TriggerVerifier();
+        mSensorManager.requestTriggerSensor(mVerifier, mSensorSignificantMotion);
+        long testStartTimeNs = SystemClock.elapsedRealtimeNanos();
+        Handler handler = new Handler(Looper.getMainLooper());
+        SuspendStateMonitor suspendStateMonitor = new SuspendStateMonitor();
+
+        Intent intent = new Intent(this, AlarmReceiver.class);
+        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
+
+        AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
+        am.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                     SystemClock.elapsedRealtime() + ALARM_WAKE_TIME_DELAY_MS, pendingIntent);
+        try {
+            // Wait for the first event to trigger. Device is expected to go into suspend here.
+            mVerifier.verifyEventTriggered();
+            long eventTimeStampNs = mVerifier.getTimeStampForTriggerEvent();
+            long endTimeNs = SystemClock.elapsedRealtimeNanos();
+            long lastWakeupTimeNs = TimeUnit.MILLISECONDS.toNanos(
+                    suspendStateMonitor.getLastWakeUpTime());
+            Assert.assertTrue(getString(R.string.snsr_device_did_not_go_into_suspend),
+                              testStartTimeNs < lastWakeupTimeNs && lastWakeupTimeNs < endTimeNs);
+            long timestampDelta = Math.abs(lastWakeupTimeNs - eventTimeStampNs);
+            Assert.assertTrue(
+                    String.format(getString(R.string.snsr_device_did_not_wake_up_at_trigger),
+                              TimeUnit.NANOSECONDS.toMillis(lastWakeupTimeNs),
+                              TimeUnit.NANOSECONDS.toMillis(eventTimeStampNs)),
+                              timestampDelta < MAX_ACCEPTABLE_DELAY_EVENT_AP_WAKE_UP_NS);
+        } finally {
+            am.cancel(pendingIntent);
+            suspendStateMonitor.cancel();
+            mScreenManipulator.turnScreenOn();
+            playSound();
+        }
+        return null;
+    }
+
     /**
      * @param instructionsResId Instruction to be shown to testers
      * @param isMotionExpected Should the device detect significant motion event
@@ -187,6 +274,27 @@
         if (mSensorSignificantMotion == null) {
             throw new SensorNotSupportedException(Sensor.TYPE_SIGNIFICANT_MOTION);
         }
+
+        mScreenManipulator = new SensorTestScreenManipulator(this);
+        try {
+            mScreenManipulator.initialize(this);
+        } catch (InterruptedException e) {
+        }
+        PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
+        LocalBroadcastManager.getInstance(this).registerReceiver(myBroadCastReceiver,
+                                            new IntentFilter(ACTION_ALARM));
+    }
+
+    @Override
+    protected void activityCleanUp() {
+        mScreenManipulator.turnScreenOff();
+        LocalBroadcastManager.getInstance(this).unregisterReceiver(myBroadCastReceiver);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mScreenManipulator.close();
     }
 
     /**
@@ -194,7 +302,7 @@
      * It cannot be reused.
      */
     private class TriggerVerifier extends TriggerEventListener {
-        private volatile CountDownLatch mCountDownLatch;
+        private volatile CountDownLatch mCountDownLatch = new CountDownLatch(1);
         private volatile TriggerEventRegistry mEventRegistry;
 
         // TODO: refactor out if needed
@@ -214,6 +322,19 @@
             mCountDownLatch.countDown();
         }
 
+        public void releaseLatch() {
+            if (mCountDownLatch != null) {
+                mCountDownLatch.countDown();
+            }
+        }
+
+        public long getTimeStampForTriggerEvent() {
+            if (mEventRegistry != null && mEventRegistry.triggerEvent != null) {
+                return mEventRegistry.triggerEvent.timestamp;
+            }
+            return 0;
+        }
+
         public String verifyEventTriggered() throws Throwable {
             TriggerEventRegistry registry = awaitForEvent();
 
@@ -267,11 +388,8 @@
         }
 
         private TriggerEventRegistry awaitForEvent() throws InterruptedException {
-            mCountDownLatch = new CountDownLatch(1);
             mCountDownLatch.await(TRIGGER_MAX_DELAY_SECONDS, TimeUnit.SECONDS);
-
             TriggerEventRegistry registry = mEventRegistry;
-            mEventRegistry = null;
 
             playSound();
             return registry != null ? registry : new TriggerEventRegistry(null, 0);
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/WifiConfigCreator.java b/common/device-side/util/src/com/android/compatibility/common/util/WifiConfigCreator.java
new file mode 100644
index 0000000..1cea80c
--- /dev/null
+++ b/common/device-side/util/src/com/android/compatibility/common/util/WifiConfigCreator.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.util;
+
+import android.content.Context;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.List;
+
+/**
+ * A simple activity to create and manage wifi configurations.
+ */
+public class WifiConfigCreator {
+    public static final String CREATE_WIFI_CONFIG_ACTION =
+            "com.android.compatibility.common.util.CREATE_WIFI_CONFIG";
+    public static final String UPDATE_WIFI_CONFIG_ACTION =
+            "com.android.compatibility.common.util.UPDATE_WIFI_CONFIG";
+    public static final String REMOVE_WIFI_CONFIG_ACTION =
+            "com.android.compatibility.common.util.REMOVE_WIFI_CONFIG";
+    public static final String EXTRA_NETID = "extra-netid";
+    public static final String EXTRA_SSID = "extra-ssid";
+    public static final String EXTRA_SECURITY_TYPE = "extra-security-type";
+    public static final String EXTRA_PASSWORD = "extra-password";
+
+    public static final int SECURITY_TYPE_NONE = 1;
+    public static final int SECURITY_TYPE_WPA = 2;
+    public static final int SECURITY_TYPE_WEP = 3;
+
+    private static final String TAG = "WifiConfigCreator";
+
+    private final WifiManager mWifiManager;
+
+    public WifiConfigCreator(Context context) {
+        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+    }
+
+    /**
+     * Adds a new WiFi network.
+     * @return network id or -1 in case of error
+     */
+    public int addNetwork(String ssid, boolean hidden, int securityType,
+            String password) throws SecurityException {
+        if (!mWifiManager.isWifiEnabled()) {
+            mWifiManager.setWifiEnabled(true);
+        }
+
+        WifiConfiguration wifiConf = createConfig(ssid, hidden, securityType, password);
+
+        int netId = mWifiManager.addNetwork(wifiConf);
+
+        if (netId != -1) {
+            mWifiManager.enableNetwork(netId, true);
+        } else {
+            Log.w(TAG, "Unable to add SSID '" + ssid + "': netId = " + netId);
+        }
+        return netId;
+    }
+
+    /**
+     * Updates a new WiFi network.
+     * @return network id (may differ from original) or -1 in case of error
+     */
+    public int updateNetwork(WifiConfiguration wifiConf, String ssid, boolean hidden,
+            int securityType, String password) throws SecurityException {
+        if (!mWifiManager.isWifiEnabled()) {
+            mWifiManager.setWifiEnabled(true);
+        }
+        if (wifiConf == null) {
+            return -1;
+        }
+
+        WifiConfiguration conf = createConfig(ssid, hidden, securityType, password);
+        conf.networkId = wifiConf.networkId;
+
+        int newNetId = mWifiManager.updateNetwork(conf);
+
+        if (newNetId != -1) {
+            mWifiManager.saveConfiguration();
+            mWifiManager.enableNetwork(newNetId, true);
+        } else {
+            Log.w(TAG, "Unable to update SSID '" + ssid + "': netId = " + newNetId);
+        }
+        return newNetId;
+    }
+
+    /**
+     * Updates a new WiFi network.
+     * @return network id (may differ from original) or -1 in case of error
+     */
+    public int updateNetwork(int netId, String ssid, boolean hidden,
+            int securityType, String password) throws SecurityException {
+        if (!mWifiManager.isWifiEnabled()) {
+            mWifiManager.setWifiEnabled(true);
+        }
+
+        WifiConfiguration wifiConf = null;
+        List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
+        for (WifiConfiguration config : configs) {
+            if (config.networkId == netId) {
+                wifiConf = config;
+                break;
+            }
+        }
+        return updateNetwork(wifiConf, ssid, hidden, securityType, password);
+    }
+
+    public boolean removeNetwork(int netId) {
+        return mWifiManager.removeNetwork(netId);
+    }
+
+    /**
+     * Creates a WifiConfiguration set up according to given parameters
+     * @param ssid SSID of the network
+     * @param hidden Is SSID not broadcast?
+     * @param securityType One of {@link #SECURITY_TYPE_NONE}, {@link #SECURITY_TYPE_WPA} or
+     *                     {@link #SECURITY_TYPE_WEP}
+     * @param password Password for WPA or WEP
+     * @return Created configuration object
+     */
+    private WifiConfiguration createConfig(String ssid, boolean hidden, int securityType,
+            String password) {
+        WifiConfiguration wifiConf = new WifiConfiguration();
+        if (!TextUtils.isEmpty(ssid)) {
+            wifiConf.SSID = '"' + ssid + '"';
+        }
+        wifiConf.status = WifiConfiguration.Status.ENABLED;
+        wifiConf.hiddenSSID = hidden;
+        switch (securityType) {
+            case SECURITY_TYPE_NONE:
+                wifiConf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+                break;
+            case SECURITY_TYPE_WPA:
+                updateForWPAConfiguration(wifiConf, password);
+                break;
+            case SECURITY_TYPE_WEP:
+                updateForWEPConfiguration(wifiConf, password);
+                break;
+        }
+        return wifiConf;
+    }
+
+    private void updateForWPAConfiguration(WifiConfiguration wifiConf, String wifiPassword) {
+        wifiConf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+        if (!TextUtils.isEmpty(wifiPassword)) {
+            wifiConf.preSharedKey = '"' + wifiPassword + '"';
+        }
+    }
+
+    private void updateForWEPConfiguration(WifiConfiguration wifiConf, String password) {
+        wifiConf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+        wifiConf.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
+        wifiConf.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
+        if (!TextUtils.isEmpty(password)) {
+            int length = password.length();
+            if ((length == 10 || length == 26
+                    || length == 58) && password.matches("[0-9A-Fa-f]*")) {
+                wifiConf.wepKeys[0] = password;
+            } else {
+                wifiConf.wepKeys[0] = '"' + password + '"';
+            }
+            wifiConf.wepTxKeyIndex = 0;
+        }
+    }
+}
+
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
index bd0089f..314f996 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner compatibility-device-util_v2
 
 LOCAL_SDK_VERSION := current
 
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
index 3b90ef9..64c7262 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/AndroidManifest.xml
@@ -21,6 +21,8 @@
 
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java
index dcb5bbc..b6815fd 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java
@@ -59,6 +59,7 @@
     }
 
     static void assertDeviceOwner(DevicePolicyManager dpm) {
+        assertNotNull(dpm);
         assertTrue(dpm.isAdminActive(getWho()));
         assertTrue(dpm.isDeviceOwnerApp(PACKAGE_NAME));
     }
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/WifiConfigLockdownTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/WifiConfigLockdownTest.java
new file mode 100644
index 0000000..ef1d8f7
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/WifiConfigLockdownTest.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.deviceowner;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import android.provider.Settings;
+
+import com.android.compatibility.common.util.WifiConfigCreator;
+
+import java.util.List;
+
+import static com.android.compatibility.common.util.WifiConfigCreator.CREATE_WIFI_CONFIG_ACTION;
+import static com.android.compatibility.common.util.WifiConfigCreator.EXTRA_NETID;
+import static com.android.compatibility.common.util.WifiConfigCreator.EXTRA_PASSWORD;
+import static com.android.compatibility.common.util.WifiConfigCreator.EXTRA_SECURITY_TYPE;
+import static com.android.compatibility.common.util.WifiConfigCreator.EXTRA_SSID;
+import static com.android.compatibility.common.util.WifiConfigCreator.REMOVE_WIFI_CONFIG_ACTION;
+import static com.android.compatibility.common.util.WifiConfigCreator.SECURITY_TYPE_NONE;
+import static com.android.compatibility.common.util.WifiConfigCreator.SECURITY_TYPE_WPA;
+import static com.android.compatibility.common.util.WifiConfigCreator.UPDATE_WIFI_CONFIG_ACTION;
+
+/**
+ * Testing WiFi configuration lockdown by Device Owner
+ */
+public class WifiConfigLockdownTest extends BaseDeviceOwnerTest {
+    private static final String TAG = "WifiConfigLockdownTest";
+    private static final String ORIGINAL_DEVICE_OWNER_SSID = "DOCTSTest";
+    private static final String CHANGED_DEVICE_OWNER_SSID = "DOChangedCTSTest";
+    private static final String ORIGINAL_REGULAR_SSID = "RegularCTSTest";
+    private static final String CHANGED_REGULAR_SSID = "RegularChangedCTSTest";
+    private static final String ORIGINAL_PASSWORD = "originalpassword";
+    private WifiManager mWifiManager;
+    private WifiConfigCreator mConfigCreator;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+        mConfigCreator = new WifiConfigCreator(mContext);
+        mDevicePolicyManager.setGlobalSetting(getWho(),
+                Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, "1");
+        mConfigCreator.addNetwork(ORIGINAL_DEVICE_OWNER_SSID, true, SECURITY_TYPE_WPA,
+                ORIGINAL_PASSWORD);
+        startRegularActivity(CREATE_WIFI_CONFIG_ACTION, -1, ORIGINAL_REGULAR_SSID,
+                SECURITY_TYPE_WPA, ORIGINAL_PASSWORD);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mDevicePolicyManager.setGlobalSetting(getWho(),
+                Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, "0");
+        List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
+        for (WifiConfiguration config : configs) {
+            if (areMatchingSsids(ORIGINAL_DEVICE_OWNER_SSID, config.SSID) ||
+                    areMatchingSsids(CHANGED_DEVICE_OWNER_SSID, config.SSID) ||
+                    areMatchingSsids(ORIGINAL_REGULAR_SSID, config.SSID) ||
+                    areMatchingSsids(CHANGED_REGULAR_SSID, config.SSID)) {
+                mWifiManager.removeNetwork(config.networkId);
+            }
+        }
+        super.tearDown();
+    }
+
+    public void testDeviceOwnerCanUpdateConfig() throws Exception {
+        List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
+        int updateCount = 0;
+        for (WifiConfiguration config : configs) {
+            if (areMatchingSsids(ORIGINAL_DEVICE_OWNER_SSID, config.SSID)) {
+                assertFalse(-1 == mConfigCreator.updateNetwork(config,
+                        CHANGED_DEVICE_OWNER_SSID, true, SECURITY_TYPE_NONE, null));
+                ++updateCount;
+            }
+            if (areMatchingSsids(ORIGINAL_REGULAR_SSID, config.SSID)) {
+                assertFalse(-1 == mConfigCreator.updateNetwork(config,
+                        CHANGED_REGULAR_SSID, true, SECURITY_TYPE_NONE, null));
+                ++updateCount;
+            }
+        }
+        assertEquals("Expected to update two configs: the DO created one and the regular one." +
+                " Instead updated: " + updateCount, 2, updateCount);
+    }
+
+    public void testDeviceOwnerCanRemoveConfig() throws Exception {
+        List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
+        int removeCount = 0;
+        for (WifiConfiguration config : configs) {
+            if (areMatchingSsids(ORIGINAL_DEVICE_OWNER_SSID, config.SSID) ||
+                    areMatchingSsids(ORIGINAL_REGULAR_SSID, config.SSID)) {
+                assertTrue(mWifiManager.removeNetwork(config.networkId));
+                ++removeCount;
+            }
+        }
+        assertEquals("Expected to remove two configs: the DO created one and the regular one." +
+                " Instead removed: " + removeCount, 2, removeCount);
+    }
+
+    public void testRegularAppCannotUpdateDeviceOwnerConfig() throws Exception {
+        List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
+        int updateCount = 0;
+        for (WifiConfiguration config : configs) {
+            if (areMatchingSsids(ORIGINAL_DEVICE_OWNER_SSID, config.SSID)) {
+                startRegularActivity(UPDATE_WIFI_CONFIG_ACTION, config.networkId,
+                        CHANGED_DEVICE_OWNER_SSID, SECURITY_TYPE_NONE, null);
+                ++updateCount;
+            }
+        }
+        assertEquals("Expected to have tried to update one config: the DO created one" +
+                " Instead tried to update: " + updateCount, 1, updateCount);
+
+        // Assert nothing has changed
+        configs = mWifiManager.getConfiguredNetworks();
+        int notChangedCount = 0;
+        for (WifiConfiguration config : configs) {
+            assertFalse(areMatchingSsids(CHANGED_DEVICE_OWNER_SSID, config.SSID));
+            if (areMatchingSsids(ORIGINAL_DEVICE_OWNER_SSID, config.SSID)) {
+                ++notChangedCount;
+            }
+        }
+        assertEquals("Expected to see one unchanged config, saw instead: " + notChangedCount, 1,
+                notChangedCount);
+    }
+
+    public void testRegularAppCannotRemoveDeviceOwnerConfig() throws Exception {
+        List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
+        int removeCount = 0;
+        for (WifiConfiguration config : configs) {
+            if (areMatchingSsids(ORIGINAL_DEVICE_OWNER_SSID, config.SSID)) {
+                startRegularActivity(REMOVE_WIFI_CONFIG_ACTION, config.networkId,
+                        null, SECURITY_TYPE_NONE, null);
+                ++removeCount;
+            }
+        }
+        assertEquals("Expected to try to remove one config: the DO created one." +
+                " Instead tried to remove: " + removeCount, 1, removeCount);
+
+        // Assert nothing has changed
+        configs = mWifiManager.getConfiguredNetworks();
+        int notChangedCount = 0;
+        for (WifiConfiguration config : configs) {
+            if (areMatchingSsids(ORIGINAL_DEVICE_OWNER_SSID, config.SSID)) {
+                ++notChangedCount;
+            }
+        }
+        assertEquals("Expected to see one unchanged config, saw instead: " + notChangedCount, 1,
+                notChangedCount);
+    }
+
+    private void startRegularActivity(String action, int netId, String ssid, int securityType,
+            String password) throws InterruptedException {
+        Intent createRegularConfig = new Intent(action);
+        createRegularConfig.putExtra(EXTRA_NETID, netId);
+        createRegularConfig.putExtra(EXTRA_SSID, ssid);
+        createRegularConfig.putExtra(EXTRA_SECURITY_TYPE, securityType);
+        createRegularConfig.putExtra(EXTRA_PASSWORD, password);
+        createRegularConfig.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(createRegularConfig);
+
+        // Give some time for the other app to finish the action
+        Thread.sleep(2000);
+    }
+
+    private boolean areMatchingSsids(String s1, String s2) {
+        if (s1 == null || s2 == null) {
+            return false;
+        }
+        return s1.replace("\"", "").equals(s2.replace("\"", ""));
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/WifiConfigCreator/Android.mk b/hostsidetests/devicepolicy/app/WifiConfigCreator/Android.mk
new file mode 100644
index 0000000..47db44e
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/WifiConfigCreator/Android.mk
@@ -0,0 +1,33 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := optional
+
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsWifiConfigCreator
+
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util_v2
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/WifiConfigCreator/AndroidManifest.xml b/hostsidetests/devicepolicy/app/WifiConfigCreator/AndroidManifest.xml
new file mode 100644
index 0000000..1b98259
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/WifiConfigCreator/AndroidManifest.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.deviceowner.wificonfigcreator">
+
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+
+    <application>
+        <activity android:name=".WifiConfigCreatorActivity"
+            android:exported="true"
+            android:theme="@android:style/Theme.NoDisplay"
+            android:noHistory="true"
+            android:autoRemoveFromRecents="true"
+            android:stateNotNeeded="true" >
+            <intent-filter>
+                <action android:name="com.android.compatibility.common.util.CREATE_WIFI_CONFIG" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="com.android.compatibility.common.util.UPDATE_WIFI_CONFIG" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="com.android.compatibility.common.util.REMOVE_WIFI_CONFIG" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
+
diff --git a/hostsidetests/devicepolicy/app/WifiConfigCreator/src/com/android/cts/deviceowner/wificonfigcreator/WifiConfigCreatorActivity.java b/hostsidetests/devicepolicy/app/WifiConfigCreator/src/com/android/cts/deviceowner/wificonfigcreator/WifiConfigCreatorActivity.java
new file mode 100644
index 0000000..7958cb1
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/WifiConfigCreator/src/com/android/cts/deviceowner/wificonfigcreator/WifiConfigCreatorActivity.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.deviceowner.wificonfigcreator;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.compatibility.common.util.WifiConfigCreator;
+import static com.android.compatibility.common.util.WifiConfigCreator.CREATE_WIFI_CONFIG_ACTION;
+import static com.android.compatibility.common.util.WifiConfigCreator.EXTRA_NETID;
+import static com.android.compatibility.common.util.WifiConfigCreator.EXTRA_PASSWORD;
+import static com.android.compatibility.common.util.WifiConfigCreator.EXTRA_SECURITY_TYPE;
+import static com.android.compatibility.common.util.WifiConfigCreator.EXTRA_SSID;
+import static com.android.compatibility.common.util.WifiConfigCreator.REMOVE_WIFI_CONFIG_ACTION;
+import static com.android.compatibility.common.util.WifiConfigCreator.SECURITY_TYPE_NONE;
+import static com.android.compatibility.common.util.WifiConfigCreator.UPDATE_WIFI_CONFIG_ACTION;
+
+/**
+ * A simple activity to create and manage wifi configurations.
+ */
+public class WifiConfigCreatorActivity extends Activity {
+    private static final String TAG = "WifiConfigCreatorActivity";
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        Log.i(TAG, "Created for user " + android.os.Process.myUserHandle());
+        WifiConfigCreator configCreator = new WifiConfigCreator(this);
+        try {
+            Intent intent = getIntent();
+            String action = intent.getAction();
+            if (CREATE_WIFI_CONFIG_ACTION.equals(action)) {
+                String ssid = intent.getStringExtra(EXTRA_SSID);
+                int securityType = intent.getIntExtra(EXTRA_SECURITY_TYPE, SECURITY_TYPE_NONE);
+                String password = intent.getStringExtra(EXTRA_PASSWORD);
+                configCreator.addNetwork(ssid, false, securityType, password);
+            } else if (UPDATE_WIFI_CONFIG_ACTION.equals(action)) {
+                int netId = intent.getIntExtra(EXTRA_NETID, -1);
+                String ssid = intent.getStringExtra(EXTRA_SSID);
+                int securityType = intent.getIntExtra(EXTRA_SECURITY_TYPE, SECURITY_TYPE_NONE);
+                String password = intent.getStringExtra(EXTRA_PASSWORD);
+                configCreator.updateNetwork(netId, ssid, false, securityType, password);
+            } else if (REMOVE_WIFI_CONFIG_ACTION.equals(action)) {
+                int netId = intent.getIntExtra(EXTRA_NETID, -1);
+                if (netId != -1) {
+                    configCreator.removeNetwork(netId);
+                }
+            } else {
+                Log.i(TAG, "Unknown command: " + action);
+            }
+        } finally {
+            finish();
+        }
+    }
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index ebdbcc7..66a123a1 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -37,6 +37,10 @@
     private static final String INTENT_RECEIVER_PKG = "com.android.cts.intent.receiver";
     private static final String INTENT_RECEIVER_APK = "CtsIntentReceiverApp.apk";
 
+    private static final String WIFI_CONFIG_CREATOR_PKG =
+            "com.android.cts.deviceowner.wificonfigcreator";
+    private static final String WIFI_CONFIG_CREATOR_APK = "CtsWifiConfigCreator.apk";
+
     private static final String ADMIN_RECEIVER_TEST_CLASS =
             DEVICE_OWNER_PKG + ".BaseDeviceOwnerTest$BasicAdminReceiver";
     private static final String CLEAR_DEVICE_OWNER_TEST_CLASS =
@@ -112,6 +116,18 @@
         executeDeviceOwnerTest("SystemUpdatePolicyTest");
     }
 
+    public void testWifiConfigLockdown() throws Exception {
+        final boolean hasWifi = hasDeviceFeature("android.hardware.wifi");
+        if (hasWifi && mHasFeature) {
+            try {
+                installApp(WIFI_CONFIG_CREATOR_APK);
+                executeDeviceOwnerTest("WifiConfigLockdownTest");
+            } finally {
+                getDevice().uninstallPackage(WIFI_CONFIG_CREATOR_PKG);
+            }
+        }
+    }
+
     private void executeDeviceOwnerTest(String testClassName) throws Exception {
         if (!mHasFeature) {
             return;
diff --git a/tests/tests/accessibility/Android.mk b/tests/tests/accessibility/Android.mk
index bb943ee..263c47b 100644
--- a/tests/tests/accessibility/Android.mk
+++ b/tests/tests/accessibility/Android.mk
@@ -26,4 +26,6 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
 
+LOCAL_SDK_VERSION := current
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/app/Android.mk b/tests/tests/app/Android.mk
index 4a3d31f..301f931 100644
--- a/tests/tests/app/Android.mk
+++ b/tests/tests/app/Android.mk
@@ -31,4 +31,6 @@
 
 LOCAL_INSTRUMENTATION_FOR := CtsAppTestStubs
 
+LOCAL_SDK_VERSION := current
+
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/app/src/android/app/cts/AlertDialog_BuilderTest.java b/tests/tests/app/src/android/app/cts/AlertDialog_BuilderTest.java
index 9554438..58e69b8 100644
--- a/tests/tests/app/src/android/app/cts/AlertDialog_BuilderTest.java
+++ b/tests/tests/app/src/android/app/cts/AlertDialog_BuilderTest.java
@@ -577,26 +577,6 @@
         assertEquals(view, mView);
     }
 
-    public void testSetViewCustom() throws Throwable {
-        final int viewSpacingLeft = 10;
-        final int viewSpacingTop = 20;
-        final int viewSpacingRight = 30;
-        final int viewSpacingBottom = 40;
-        final View view = new View(mContext);
-        view.setId(100);
-        runTestOnUiThread(new Runnable() {
-            public void run() {
-                mBuilder = new AlertDialog.Builder(mContext);
-                mBuilder.setView(view, viewSpacingLeft, viewSpacingTop, viewSpacingRight,
-                        viewSpacingBottom);
-                mDialog = mBuilder.show();
-                mView = mDialog.getWindow().findViewById(100);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertEquals(view, mView);
-    }
-
     public void testSetInverseBackgroundForced() throws Throwable {
         runTestOnUiThread(new Runnable() {
             public void run() {
diff --git a/tests/tests/app/src/android/app/cts/InstrumentationTest.java b/tests/tests/app/src/android/app/cts/InstrumentationTest.java
index b21148e..25403f3 100644
--- a/tests/tests/app/src/android/app/cts/InstrumentationTest.java
+++ b/tests/tests/app/src/android/app/cts/InstrumentationTest.java
@@ -540,7 +540,6 @@
             public void openPanel(int featureId, KeyEvent event) {
             }
 
-            @Override
             public void alwaysReadCloseOnTouchAttr() {
             }
 
diff --git a/tests/tests/app/src/android/app/cts/NotificationTest.java b/tests/tests/app/src/android/app/cts/NotificationTest.java
index 17f433e..6179922 100644
--- a/tests/tests/app/src/android/app/cts/NotificationTest.java
+++ b/tests/tests/app/src/android/app/cts/NotificationTest.java
@@ -166,16 +166,6 @@
         assertNotNull(mNotification.contentView);
     }
 
-    public void testSetLatestEventInfo() {
-        mNotification = new Notification();
-        mNotification.icon = 1;
-        final Intent intent = new Intent();
-        final PendingIntent contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
-        mNotification.setLatestEventInfo(mContext, CONTENT_TITLE, CONTENT_TEXT, contentIntent);
-        assertTrue(mNotification.contentView instanceof RemoteViews);
-        assertNotNull(mNotification.contentView);
-    }
-
     public void testToString() {
         mNotification = new Notification();
         assertNotNull(mNotification.toString());
diff --git a/tests/tests/app/src/android/app/cts/SearchDialogTest.java b/tests/tests/app/src/android/app/cts/SearchDialogTest.java
deleted file mode 100644
index 1cf1ebd..0000000
--- a/tests/tests/app/src/android/app/cts/SearchDialogTest.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.cts;
-
-import android.app.SearchDialog;
-import android.content.Context;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.InstrumentationTestCase;
-import android.view.ActionMode;
-import android.view.View;
-import android.view.ViewGroup;
-
-/**
- * Test {@link SearchDialog}.
- */
-public class SearchDialogTest extends InstrumentationTestCase {
-
-    private Context mContext;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mContext = getInstrumentation().getTargetContext();
-    }
-
-    public void testPrimaryActionModesAreStopped() {
-        SearchDialog.SearchBar searchBar = new SearchDialog.SearchBar(mContext);
-        MockViewGroup viewGroup = new MockViewGroup(mContext);
-        viewGroup.addView(searchBar);
-
-        ActionMode mode = searchBar.startActionModeForChild(null, null, ActionMode.TYPE_PRIMARY);
-
-        assertNull(mode);
-        // Should not bubble up.
-        assertFalse(viewGroup.isStartActionModeForChildTypedCalled);
-        assertFalse(viewGroup.isStartActionModeForChildTypelessCalled);
-
-        mode = searchBar.startActionModeForChild(null, null);
-
-        assertNull(mode);
-        // Should not bubble up.
-        assertFalse(viewGroup.isStartActionModeForChildTypedCalled);
-        assertFalse(viewGroup.isStartActionModeForChildTypelessCalled);
-    }
-
-    public void testFloatingActionModesAreBubbledUp() {
-        SearchDialog.SearchBar searchBar = new SearchDialog.SearchBar(mContext);
-        MockViewGroup viewGroup = new MockViewGroup(mContext);
-        viewGroup.addView(searchBar);
-
-        searchBar.startActionModeForChild(null, null, ActionMode.TYPE_FLOATING);
-
-        // Should bubble up.
-        assertTrue(viewGroup.isStartActionModeForChildTypedCalled);
-    }
-
-    private static class MockViewGroup extends ViewGroup {
-        boolean isStartActionModeForChildTypedCalled = false;
-        boolean isStartActionModeForChildTypelessCalled = false;
-
-        public MockViewGroup(Context context) {
-            super(context);
-        }
-
-        @Override
-        public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
-            isStartActionModeForChildTypelessCalled = true;
-            return super.startActionModeForChild(originalView, callback);
-        }
-
-        @Override
-        public ActionMode startActionModeForChild(
-                View originalView, ActionMode.Callback callback, int type) {
-            isStartActionModeForChildTypedCalled = true;
-            return super.startActionModeForChild(originalView, callback, type);
-        }
-
-        @Override
-        protected void onLayout(boolean changed, int l, int t, int r, int b) {}
-    }
-}
diff --git a/tests/tests/content/src/android/content/cts/HighPriorityBroadcastReceiver.java b/tests/tests/content/src/android/content/cts/HighPriorityBroadcastReceiver.java
index f3a4ba1..187fe06 100644
--- a/tests/tests/content/src/android/content/cts/HighPriorityBroadcastReceiver.java
+++ b/tests/tests/content/src/android/content/cts/HighPriorityBroadcastReceiver.java
@@ -22,13 +22,11 @@
 public class HighPriorityBroadcastReceiver extends ResultReceiver {
 
     @Override
-    public void onReceive(Context context, Intent intent) {
+    public synchronized void onReceive(Context context, Intent intent) {
         super.onReceive(context, intent);
 
         try {
-            synchronized (this) {
-                wait();
-            }
+            wait();
         } catch (InterruptedException e) {
             throw new RuntimeException("Got interrupted during wait()", e);
         }
diff --git a/tests/tests/graphics/src/android/graphics/cts/VulkanReservedTest.java b/tests/tests/graphics/src/android/graphics/cts/VulkanReservedTest.java
new file mode 100644
index 0000000..bfd520e
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/VulkanReservedTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.graphics.cts;
+
+import android.cts.util.FileUtils;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+
+public class VulkanReservedTest extends TestCase {
+
+    /**
+     * Assert that file with given path does not exist.
+     */
+    private static void assertNoFile(String filename) {
+        assertFalse(filename + " must not exist", new File(filename).exists());
+    }
+
+    /**
+     * Test that no vendor ships libvulkan.so before ratification and
+     * appropriate CTS coverage.
+     */
+    public void testNoVulkan() {
+        assertNoFile("/system/lib/libvulkan.so");
+        assertNoFile("/system/lib64/libvulkan.so");
+        assertNoFile("/vendor/lib/libvulkan.so");
+        assertNoFile("/vendor/lib64/libvulkan.so");
+    }
+}
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/IconTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/IconTest.java
new file mode 100644
index 0000000..d89ce7c
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/IconTest.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.graphics.drawable.cts;
+
+import com.android.cts.graphics.R;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.res.ColorStateList;
+import android.graphics.Bitmap;
+import android.graphics.cts.ImageViewCtsActivity;
+import android.graphics.drawable.Icon;
+import android.graphics.drawable.Drawable;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Parcel;
+import android.test.ActivityInstrumentationTestCase2;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class IconTest extends ActivityInstrumentationTestCase2<ImageViewCtsActivity> {
+    static final long TIMEOUT = 1000;
+
+    Activity mActivity;
+    Instrumentation mInstrumentation;
+    Icon mIcon;
+
+    MockOnDrawableLoadedListener mListener;
+    MockRunner mRunner;
+
+    public IconTest() {
+        super("com.android.cts.graphics", ImageViewCtsActivity.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+        mInstrumentation = getInstrumentation();
+    }
+
+    public void testBitmapIcon() {
+        checkIconValidity(
+                Icon.createWithBitmap(Bitmap.createBitmap(16, 16, Bitmap.Config.ARGB_8888)));
+    }
+
+    public void testDataIcon() {
+        byte[] data = new byte[4];
+        data[0] = data[1] = data[2] = data[3] = (byte)255;
+        checkIconValidity(Icon.createWithData(data, 0, 4));
+    }
+
+    public void testFileIcon() throws IOException {
+        File file = new File(mActivity.getFilesDir(), "testimage.jpg");
+        try {
+            writeSampleImage(file);
+            assertTrue(file.exists());
+
+            checkIconValidity(Icon.createWithFilePath(file.getPath()));
+
+            checkIconValidity(Icon.createWithContentUri(Uri.fromFile(file)));
+
+            checkIconValidity(Icon.createWithContentUri(file.toURI().toString()));
+        } finally {
+            file.delete();
+        }
+    }
+
+    public void testResourceIcon() {
+        checkIconValidity(Icon.createWithResource(mActivity, R.drawable.bmp_test));
+
+        checkIconValidity(Icon.createWithResource(mActivity.getPackageName(), R.drawable.bmp_test));
+    }
+
+    public void testLoadDrawableAsync() {
+        mIcon = Icon.createWithBitmap(Bitmap.createBitmap(16, 16, Bitmap.Config.ARGB_8888));
+
+        mListener = new MockOnDrawableLoadedListener();
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mIcon.loadDrawableAsync(mActivity, mListener, new Handler());
+            }
+        });
+        sleep(TIMEOUT);
+
+        assertEquals(1, mListener.getLoadedCount());
+    }
+
+    public void testLoadDrawableAsyncWithMessage() {
+        mIcon = Icon.createWithBitmap(Bitmap.createBitmap(16, 16, Bitmap.Config.ARGB_8888));
+
+        mRunner = new MockRunner();
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mIcon.loadDrawableAsync(mActivity, Message.obtain(new Handler(), mRunner));
+            }
+        });
+        sleep(TIMEOUT);
+
+        assertEquals(1, mRunner.getRunCount());
+    }
+
+    class MockOnDrawableLoadedListener implements Icon.OnDrawableLoadedListener {
+        int mLoadedCount;
+
+        @Override
+        public void onDrawableLoaded(Drawable d) {
+            assertNotNull(d);
+            ++mLoadedCount;
+        }
+
+        int getLoadedCount() { return mLoadedCount; }
+    }
+
+    class MockRunner implements Runnable {
+        int mRun;
+
+        @Override
+        public void run() {
+            ++mRun;
+        }
+
+        int getRunCount() { return mRun; }
+    };
+
+    private void sleep(long time) {
+        try {
+            Thread.sleep(time);
+        } catch (InterruptedException e) {
+            fail(e.getMessage());
+        }
+    }
+
+    private void writeSampleImage(File imagefile) throws IOException {
+        InputStream source = null;
+        OutputStream target = null;
+
+        try {
+            source = mActivity.getResources().openRawResource(R.drawable.testimage);
+            target = new FileOutputStream(imagefile);
+
+            byte[] buffer = new byte[1024];
+            for (int len = source.read(buffer); len >= 0; len = source.read(buffer)) {
+                target.write(buffer, 0, len);
+            }
+        } finally {
+            if (target != null) {
+                target.close();
+            }
+
+            if (source != null) {
+                source.close();
+            }
+        }
+    }
+
+    // Check if the created icon is valid and doesn't cause crashes for the public methods.
+    private void checkIconValidity(Icon icon) {
+        assertNotNull(icon);
+
+        // tint properties.
+        icon.setTint(Color.BLUE);
+        icon.setTintList(ColorStateList.valueOf(Color.RED));
+        icon.setTintMode(PorterDuff.Mode.XOR);
+
+        // Parcelable methods.
+        icon.describeContents();
+        Parcel parcel = Parcel.obtain();
+        icon.writeToParcel(parcel, 0);
+
+        parcel.setDataPosition(0);
+        assertNotNull(Icon.CREATOR.createFromParcel(parcel));
+
+        // loading drawable synchronously.
+        assertNotNull(icon.loadDrawable(mActivity));
+    }
+}
diff --git a/tests/tests/graphics/src/android/opengl/cts/EglConfigGLSurfaceView.java b/tests/tests/graphics/src/android/opengl/cts/EglConfigGLSurfaceView.java
index 03e8d94..eb36166 100644
--- a/tests/tests/graphics/src/android/opengl/cts/EglConfigGLSurfaceView.java
+++ b/tests/tests/graphics/src/android/opengl/cts/EglConfigGLSurfaceView.java
@@ -101,7 +101,7 @@
             gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
             gl.glColor4f(1.0f, 0, 0, 0);
             gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFloatBuffer);
-            gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 9);
+            gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
 
             if (++mNumFrames == 10) {
                 post(mCallback);
diff --git a/tests/tests/hardware/AndroidTest.xml b/tests/tests/hardware/AndroidTest.xml
index 783eafe..4ddf28c 100644
--- a/tests/tests/hardware/AndroidTest.xml
+++ b/tests/tests/hardware/AndroidTest.xml
@@ -17,6 +17,6 @@
     <include name="common-config" />
     <!-- Put SensorService in restricted mode so that only CTS tests will be able to get access to
     sensors -->
-    <option name="run-command:run-command" value="dumpsys sensorservice restrict" />
+    <option name="run-command:run-command" value="dumpsys sensorservice restrict .cts." />
     <option name="run-command:teardown-command" value="dumpsys sensorservice enable" />
 </configuration>
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
index ad1951c..cd4b731 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
@@ -60,7 +60,7 @@
     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
     private static final boolean DEBUG_DUMP = Log.isLoggable(TAG, Log.DEBUG);
     private static final int RECORDING_DURATION_MS = 3000;
-    private static final int DURATION_MARGIN_MS = 600;
+    private static final float DURATION_MARGIN = 0.2f;
     private static final double FRAME_DURATION_ERROR_TOLERANCE_MS = 3.0;
     private static final int BIT_RATE_1080P = 16000000;
     private static final int BIT_RATE_MIN = 64000;
@@ -1080,7 +1080,7 @@
         }
     }
 
-    private void validateRecording(Size sz, int durationMs) throws Exception {
+    private void validateRecording(Size sz, int expectedDurationMs) throws Exception {
         File outFile = new File(mOutMediaFileName);
         assertTrue("No video is recorded", outFile.exists());
 
@@ -1108,15 +1108,16 @@
             int duration = (int) (durationUs / 1000);
             if (VERBOSE) {
                 Log.v(TAG, String.format("Video duration: recorded %dms, expected %dms",
-                                         duration, durationMs));
+                                         duration, expectedDurationMs));
             }
 
             // TODO: Don't skip this for video snapshot
             if (!mStaticInfo.isHardwareLevelLegacy()) {
                 assertTrue(String.format(
                         "Camera %s: Video duration doesn't match: recorded %dms, expected %dms.",
-                        mCamera.getId(), duration, durationMs),
-                        Math.abs(duration - durationMs) < DURATION_MARGIN_MS);
+                        mCamera.getId(), duration, expectedDurationMs),
+                        Math.abs(duration - expectedDurationMs) <
+                        DURATION_MARGIN * expectedDurationMs);
             }
         } finally {
             extractor.release();
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
index ee4ddd9..d8dda8f 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
@@ -341,6 +341,12 @@
                 Log.i(TAG, "Testing AE precapture cancel for jpeg capture for Camera " + id);
                 openDevice(id);
 
+                // Legacy device doesn't support AE precapture trigger
+                if (mStaticInfo.isHardwareLevelLegacy()) {
+                    Log.i(TAG, "Skipping AE precapture trigger cancel test on legacy devices");
+                    continue;
+                }
+
                 takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, /*afRegions*/null,
                         /*addAeTriggerCancel*/true);
             } finally {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/RawConverter.java b/tests/tests/hardware/src/android/hardware/camera2/cts/rs/RawConverter.java
index f97c08f..818b6c0 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/RawConverter.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/rs/RawConverter.java
@@ -608,8 +608,11 @@
         float[] referenceNeutral = new float[3];
         map(inverseInterpolatedCC, cameraNeutral, /*out*/referenceNeutral);
         if (DEBUG) Log.d(TAG, "Reference neutral: " + Arrays.toString(referenceNeutral));
-        float[] D = new float[] { 1/referenceNeutral[0], 0, 0,  0, 1/referenceNeutral[1], 0, 0, 0,
-                1/referenceNeutral[2] };
+        float maxNeutral = Math.max(Math.max(referenceNeutral[0], referenceNeutral[1]),
+                referenceNeutral[2]);
+        float[] D = new float[] { maxNeutral/referenceNeutral[0], 0, 0,
+                                  0, maxNeutral/referenceNeutral[1], 0,
+                                  0, 0, maxNeutral/referenceNeutral[2] };
         if (DEBUG) Log.d(TAG, "Reference Neutral Diagonal: " + Arrays.toString(D));
 
         float[] intermediate = new float[9];
diff --git a/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java b/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
old mode 100644
new mode 100755
index 0e09e8c..0a0607d
--- a/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
@@ -152,7 +152,7 @@
     private void assertMinMemoryMb(long minMb) {
 
         long totalMemoryMb = getTotalMemory() / ONE_MEGABYTE;
-        boolean lowRam = totalMemoryMb <= minMb * 1.5;
+        boolean lowRam = totalMemoryMb <= 512;
         boolean lowRamDevice = mActivityManager.isLowRamDevice();
 
         Log.i(TAG, String.format("minMb=%,d", minMb));
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
index 4450339..6beeec8 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
@@ -348,9 +348,9 @@
         TestSensorEventListener listener = new TestSensorEventListener(environment, handler);
 
         CountDownLatch eventLatch = mTestSensorManager.registerListener(listener, 1);
-        listener.waitForEvents(eventLatch, 1);
+        listener.waitForEvents(eventLatch, 1, true);
         CountDownLatch flushLatch = mTestSensorManager.requestFlush();
-        listener.waitForFlushComplete(flushLatch);
+        listener.waitForFlushComplete(flushLatch, true);
         listener.assertEventsReceivedInHandler();
     }
 
@@ -382,9 +382,9 @@
 
         // specifyHandler <= false, use the SensorManager API without Handler parameter
         CountDownLatch eventLatch = mTestSensorManager.registerListener(listener, 1, false);
-        listener.waitForEvents(eventLatch, 1);
+        listener.waitForEvents(eventLatch, 1, true);
         CountDownLatch flushLatch = mTestSensorManager.requestFlush();
-        listener.waitForFlushComplete(flushLatch);
+        listener.waitForFlushComplete(flushLatch, true);
         listener.assertEventsReceivedInHandler();
     }
 
@@ -581,10 +581,10 @@
             try {
                 CountDownLatch eventLatch = sensorManager.registerListener(listener, mEventCount);
                 if (sensorReportingMode == Sensor.REPORTING_MODE_CONTINUOUS) {
-                    listener.waitForEvents(eventLatch, mEventCount);
+                    listener.waitForEvents(eventLatch, mEventCount, true);
                 }
                 CountDownLatch flushLatch = sensorManager.requestFlush();
-                listener.waitForFlushComplete(flushLatch);
+                listener.waitForFlushComplete(flushLatch, true);
             } finally {
                 sensorManager.unregisterListener();
             }
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorNotSupportedException.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorNotSupportedException.java
index e727092..0d90957 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorNotSupportedException.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorNotSupportedException.java
@@ -26,6 +26,11 @@
         super("Sensor '%s' of type %d is not supported.", getSensorName(sensorType), sensorType);
     }
 
+    public SensorNotSupportedException(int sensorType, boolean wakeup) {
+        super("Sensor '%s' of type %d and %s is not supported.", getSensorName(sensorType),
+               sensorType, wakeup ? "wake-up" : "non wake-up");
+    }
+
     private static String getSensorName(int sensorType) {
         return String.format("%s (%d)", getSimpleSensorName(sensorType), sensorType);
     }
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java
index 8067aed..f0f0186 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java
@@ -54,6 +54,7 @@
     public static final String MEAN_KEY = "mean";
     public static final String STANDARD_DEVIATION_KEY = "standard_deviation";
     public static final String MAGNITUDE_KEY = "magnitude";
+    public static final String DELAYED_BATCH_DELIVERY = "delayed_batch_delivery";
 
     private final Map<String, Object> mValues = new HashMap<>();
     private final Map<String, SensorStats> mSensorStats = new HashMap<>();
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SuspendStateMonitor.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SuspendStateMonitor.java
new file mode 100644
index 0000000..4426967
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SuspendStateMonitor.java
@@ -0,0 +1,57 @@
+package android.hardware.cts.helpers;
+
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import android.hardware.Sensor;
+import android.hardware.TriggerEvent;
+import android.hardware.TriggerEventListener;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.util.Log;
+
+import junit.framework.Assert;
+
+public class SuspendStateMonitor {
+    private final double firstRealTimeMillis;
+    private final double firstUpTimeMillis;
+    private double lastSleepTimeSeconds = 0;
+    private volatile long lastWakeUpTime = 0;
+    Timer sleepMonitoringTimer = new Timer();
+
+    /**
+     * Returns the time the device slept since the start of the application,
+     * in seconds.
+     */
+    public double getSleepTimeSeconds() {
+        double totalSinceStart = android.os.SystemClock.elapsedRealtime() - firstRealTimeMillis;
+        double upTimeSinceStart = android.os.SystemClock.uptimeMillis() - firstUpTimeMillis;
+        return (totalSinceStart - upTimeSinceStart) / 1000;
+    }
+
+    public long getLastWakeUpTime() {
+        return lastWakeUpTime;
+    }
+
+    public void cancel() {
+        sleepMonitoringTimer.cancel();
+    }
+
+     public SuspendStateMonitor() {
+        firstRealTimeMillis = android.os.SystemClock.elapsedRealtime();
+        firstUpTimeMillis = android.os.SystemClock.uptimeMillis();
+        // Every 100 miliseconds, check whether the device has slept.
+        TimerTask sleepMonitoringTask = new TimerTask() {
+                @Override
+                public void run() {
+                    if (getSleepTimeSeconds() - lastSleepTimeSeconds > 0.1) {
+                        lastSleepTimeSeconds = getSleepTimeSeconds();
+                        lastWakeUpTime = SystemClock.elapsedRealtime();
+                    }
+                }
+        };
+        sleepMonitoringTimer.schedule(sleepMonitoringTask, 0, 100);
+    }
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java
index 143f0a1..6156d3d 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java
@@ -40,6 +40,7 @@
     private final boolean mSensorMightHaveMoreListeners;
     private final int mSamplingPeriodUs;
     private final int mMaxReportLatencyUs;
+    private final boolean mIsDeviceSuspendTest;
 
     /**
      * Constructs an environment for sensor testing.
@@ -163,11 +164,27 @@
             boolean sensorMightHaveMoreListeners,
             int samplingPeriodUs,
             int maxReportLatencyUs) {
+        this(context,
+                sensor,
+                sensorMightHaveMoreListeners,
+                samplingPeriodUs,
+                maxReportLatencyUs,
+                false /* isDeviceSuspendTest */);
+    }
+
+    public TestSensorEnvironment(
+            Context context,
+            Sensor sensor,
+            boolean sensorMightHaveMoreListeners,
+            int samplingPeriodUs,
+            int maxReportLatencyUs,
+            boolean isDeviceSuspendTest) {
         mContext = context;
         mSensor = sensor;
         mSensorMightHaveMoreListeners = sensorMightHaveMoreListeners;
         mSamplingPeriodUs = samplingPeriodUs;
         mMaxReportLatencyUs = maxReportLatencyUs;
+        mIsDeviceSuspendTest = isDeviceSuspendTest;
     }
 
     /**
@@ -357,4 +374,9 @@
                 && mSamplingPeriodUs != SensorManager.SENSOR_DELAY_UI
                 && mSamplingPeriodUs != SensorManager.SENSOR_DELAY_NORMAL);
     }
+
+    public boolean isDeviceSuspendTest() {
+        return mIsDeviceSuspendTest;
+    }
 }
+
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
index 662c3ce..23effb9 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
@@ -18,12 +18,16 @@
 
 import junit.framework.Assert;
 
+import android.content.Context;
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener2;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.SystemClock;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.util.Log;
 
 import java.io.BufferedWriter;
 import java.io.File;
@@ -50,12 +54,14 @@
     private static final long FLUSH_TIMEOUT_US = TimeUnit.SECONDS.toMicros(10);
 
     private final ArrayList<TestSensorEvent> mCollectedEvents = new ArrayList<>();
+    private final ArrayList<Long> mTimeStampFlushCompleteEvents = new ArrayList<>();
     private final List<CountDownLatch> mEventLatches = new ArrayList<>();
     private final List<CountDownLatch> mFlushLatches = new ArrayList<>();
     private final AtomicInteger mEventsReceivedOutsideHandler = new AtomicInteger();
 
     private final Handler mHandler;
     private final TestSensorEnvironment mEnvironment;
+    private final PowerManager.WakeLock mTestSensorEventListenerWakeLock;
 
     /**
      * @deprecated Use {@link TestSensorEventListener(TestSensorEnvironment)}.
@@ -78,6 +84,10 @@
     public TestSensorEventListener(TestSensorEnvironment environment, Handler handler) {
         mEnvironment = environment;
         mHandler = handler;
+        PowerManager pm = (PowerManager) environment.getContext().getSystemService(
+                Context.POWER_SERVICE);
+        mTestSensorEventListenerWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+                                                "TestSensorEventListenerWakeLock");
     }
 
     /**
@@ -93,6 +103,9 @@
         synchronized (mEventLatches) {
             for (CountDownLatch latch : mEventLatches) {
                 latch.countDown();
+                if (latch.getCount() == 0 && !mTestSensorEventListenerWakeLock.isHeld()) {
+                    mTestSensorEventListenerWakeLock.acquire();
+                }
             }
         }
     }
@@ -136,6 +149,10 @@
     @Override
     public void onFlushCompleted(Sensor sensor) {
         checkHandler();
+        long timestampNs = SystemClock.elapsedRealtimeNanos();
+        synchronized (mTimeStampFlushCompleteEvents) {
+           mTimeStampFlushCompleteEvents.add(timestampNs);
+        }
         synchronized (mFlushLatches) {
             for (CountDownLatch latch : mFlushLatches) {
                 latch.countDown();
@@ -175,7 +192,8 @@
      * It will overwrite the file if it already exists, the file is created in a relative directory
      * named 'events' under the sensor test directory (part of external storage).
      */
-    public void logCollectedEventsToFile(String fileName) throws IOException {
+    public void logCollectedEventsToFile(String fileName, long deviceWakeUpTimeMs)
+        throws IOException {
         StringBuilder builder = new StringBuilder();
         builder.append("Sensor='").append(mEnvironment.getSensor()).append("', ");
         builder.append("SamplingRateOverloaded=")
@@ -184,15 +202,54 @@
                 .append(mEnvironment.getRequestedSamplingPeriodUs()).append("us, ");
         builder.append("MaxReportLatency=")
                 .append(mEnvironment.getMaxReportLatencyUs()).append("us");
-
         synchronized (mCollectedEvents) {
-            for (TestSensorEvent event : mCollectedEvents) {
+            int i = 0, j = 0;
+            while (i < mCollectedEvents.size() && j < mTimeStampFlushCompleteEvents.size()) {
+                if (mCollectedEvents.get(i).receivedTimestamp <
+                        mTimeStampFlushCompleteEvents.get(j)) {
+                    TestSensorEvent event = mCollectedEvents.get(i);
+                    if (deviceWakeUpTimeMs != -1 && deviceWakeUpTimeMs <
+                            event.receivedTimestamp/1000000) {
+                        builder.append("\n");
+                        builder.append("AP wake-up time=").append(deviceWakeUpTimeMs).append("ms");
+                        deviceWakeUpTimeMs = -1;
+                    }
+                    builder.append("\n");
+                    builder.append("Timestamp=").append(event.timestamp/1000000).append("ms, ");
+                    builder.append("ReceivedTimestamp=").append(event.receivedTimestamp/1000000).
+                        append("ms, ");
+                    builder.append("Accuracy=").append(event.accuracy).append(", ");
+                    builder.append("Values=").append(Arrays.toString(event.values));
+                    ++i;
+                } else {
+                    builder.append("\n");
+                    builder.append("ReceivedTimestamp=")
+                    .append(mTimeStampFlushCompleteEvents.get(j)/1000000)
+                    .append(" Flush complete Event");
+                    ++j;
+                }
+            }
+            for (;i < mCollectedEvents.size(); ++i) {
+                TestSensorEvent event = mCollectedEvents.get(i);
+                if (deviceWakeUpTimeMs != -1 && deviceWakeUpTimeMs <
+                        event.receivedTimestamp/1000000) {
+                    builder.append("\n");
+                    builder.append("AP wake-up time=").append(deviceWakeUpTimeMs).append("ms");
+                    deviceWakeUpTimeMs = -1;
+                }
                 builder.append("\n");
-                builder.append("Timestamp=").append(event.timestamp).append("ns, ");
-                builder.append("ReceivedTimestamp=").append(event.receivedTimestamp).append("ns, ");
+                builder.append("Timestamp=").append(event.timestamp/1000000).append("ms, ");
+                builder.append("ReceivedTimestamp=").append(event.receivedTimestamp/1000000).
+                    append("ms, ");
                 builder.append("Accuracy=").append(event.accuracy).append(", ");
                 builder.append("Values=").append(Arrays.toString(event.values));
             }
+            for (;j < mTimeStampFlushCompleteEvents.size(); ++j) {
+                builder.append("\n");
+                builder.append("ReceivedTimestamp=")
+                    .append(mTimeStampFlushCompleteEvents.get(j)/1000000)
+                    .append("ms Flush complete Event");
+            }
         }
 
         File eventsDirectory = SensorCtsHelper.getSensorTestDataDirectory("events/");
@@ -208,8 +265,11 @@
      *
      * @throws AssertionError if there was a timeout after {@link #FLUSH_TIMEOUT_US} &micro;s
      */
-    public void waitForFlushComplete(CountDownLatch latch) throws InterruptedException {
-        clearEvents();
+    public void waitForFlushComplete(CountDownLatch latch,
+                                      boolean clearCollectedEvents) throws InterruptedException {
+        if (clearCollectedEvents) {
+            clearEvents();
+        }
         try {
             String message = SensorCtsHelper.formatAssertionMessage(
                     "WaitForFlush",
@@ -229,8 +289,11 @@
      *
      * @throws AssertionError if there was a timeout after {@link #FLUSH_TIMEOUT_US} &micro;s
      */
-    public void waitForEvents(CountDownLatch latch, int eventCount) throws InterruptedException {
-        clearEvents();
+    public void waitForEvents(CountDownLatch latch, int eventCount,
+                               boolean clearCollectedEvents) throws InterruptedException {
+        if (clearCollectedEvents) {
+            clearEvents();
+        }
         try {
             long samplingPeriodUs = mEnvironment.getMaximumExpectedSamplingPeriodUs();
             // timeout is 2 * event count * expected period + batch timeout + default wait
@@ -279,6 +342,12 @@
         Assert.assertEquals(message, 0 /* expected */, eventsOutsideHandler);
     }
 
+    public void releaseWakeLock() {
+        if (mTestSensorEventListenerWakeLock.isHeld()) {
+            mTestSensorEventListenerWakeLock.release();
+        }
+    }
+
     /**
      * Keeps track of the number of events that arrived in a different {@link Looper} than the one
      * associated with the {@link TestSensorEventListener}.
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
index 3b90b15..d6cc54e 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
@@ -16,7 +16,11 @@
 
 package android.hardware.cts.helpers.sensoroperations;
 
-import junit.framework.Assert;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 import android.hardware.cts.helpers.SensorCtsHelper;
 import android.hardware.cts.helpers.SensorStats;
@@ -25,6 +29,7 @@
 import android.hardware.cts.helpers.TestSensorEvent;
 import android.hardware.cts.helpers.TestSensorEventListener;
 import android.hardware.cts.helpers.TestSensorManager;
+import android.hardware.cts.helpers.SuspendStateMonitor;
 import android.hardware.cts.helpers.reporting.ISensorTestNode;
 import android.hardware.cts.helpers.sensorverification.EventGapVerification;
 import android.hardware.cts.helpers.sensorverification.EventOrderingVerification;
@@ -36,13 +41,11 @@
 import android.hardware.cts.helpers.sensorverification.MeanVerification;
 import android.hardware.cts.helpers.sensorverification.StandardDeviationVerification;
 import android.os.Handler;
+import android.os.SystemClock;
+import android.os.PowerManager.WakeLock;
 import android.util.Log;
 
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
+import junit.framework.Assert;
 
 /**
  * A {@link SensorOperation} used to verify that sensor events and sensor values are correct.
@@ -61,6 +64,7 @@
     private final TestSensorEnvironment mEnvironment;
     private final Executor mExecutor;
     private final Handler mHandler;
+    private long mDeviceWakeUpTimeMs = -1;
 
     /**
      * An interface that defines an abstraction for operations to be performed by the
@@ -118,7 +122,22 @@
     public void execute(ISensorTestNode parent) throws InterruptedException {
         getStats().addValue("sensor_name", mEnvironment.getSensor().getName());
         TestSensorEventListener listener = new TestSensorEventListener(mEnvironment, mHandler);
-        mExecutor.execute(mSensorManager, listener);
+
+        if (mEnvironment.isDeviceSuspendTest()) {
+            SuspendStateMonitor suspendStateMonitor = new SuspendStateMonitor();
+            long startTimeMs = SystemClock.elapsedRealtime();
+            // Device should go into suspend here.
+            mExecutor.execute(mSensorManager, listener);
+            long endTimeMs = SystemClock.elapsedRealtime();
+            // Check if the device has gone into suspend during test execution.
+            mDeviceWakeUpTimeMs = suspendStateMonitor.getLastWakeUpTime();
+            suspendStateMonitor.cancel();
+            Assert.assertTrue("Device did not go into suspend during test execution",
+                                       startTimeMs < mDeviceWakeUpTimeMs &&
+                                       mDeviceWakeUpTimeMs < endTimeMs);
+        } else {
+            mExecutor.execute(mSensorManager, listener);
+        }
 
         boolean failed = false;
         StringBuilder sb = new StringBuilder();
@@ -193,7 +212,7 @@
         }
 
         try {
-            listener.logCollectedEventsToFile(sanitizedFileName);
+            listener.logCollectedEventsToFile(sanitizedFileName, mDeviceWakeUpTimeMs);
         } catch (IOException e) {
             Log.w(TAG, "Unable to save collected events to file: " + sanitizedFileName, e);
         }
@@ -214,7 +233,7 @@
                     throws InterruptedException {
                 try {
                     CountDownLatch latch = sensorManager.registerListener(listener, eventCount);
-                    listener.waitForEvents(latch, eventCount);
+                    listener.waitForEvents(latch, eventCount, true);
                 } finally {
                     sensorManager.unregisterListener();
                 }
@@ -224,6 +243,62 @@
     }
 
     /**
+     * Creates an operation that will wait for a given amount of events to arrive.
+     *
+     * @param environment The test environment.
+     * @param eventCount The number of events to wait for.
+     */
+    public static TestSensorOperation createOperation(
+            final TestSensorEnvironment environment,
+            final int eventCount,
+            final WakeLock wakeLock,
+            final boolean flushRequested) {
+        Executor executor = new Executor() {
+            @Override
+            public void execute(TestSensorManager sensorManager, TestSensorEventListener listener)
+                    throws InterruptedException {
+                try {
+                    int eventCountForLatch = eventCount;
+                    if (flushRequested) {
+                        eventCountForLatch = eventCount + (int)environment.getFrequencyHz();
+                    }
+                    CountDownLatch latch = sensorManager.registerListener(listener,
+                                                                           eventCountForLatch);
+                    if (flushRequested) {
+                        SensorCtsHelper.sleep(1, TimeUnit.SECONDS);
+                        CountDownLatch flushLatch = sensorManager.requestFlush();
+                        listener.waitForFlushComplete(flushLatch, false);
+                    }
+                    if (wakeLock.isHeld()) {
+                        wakeLock.release();
+                    }
+                    listener.releaseWakeLock();
+                    Log.v("TestSensorOperation", "waitForEvents " +
+                            environment.getSensor().getName()
+                          + " " + latch.getCount());
+                    listener.waitForEvents(latch, eventCount, false);
+                    Log.v("TestSensorOperation", "waitForEvents DONE " + environment.getSensor().getName());
+                    if (!wakeLock.isHeld()) {
+                        wakeLock.acquire();
+                    }
+                    if (flushRequested) {
+                        SensorCtsHelper.sleep(1, TimeUnit.SECONDS);
+                        CountDownLatch flushLatch = sensorManager.requestFlush();
+                        listener.waitForFlushComplete(flushLatch, false);
+                    }
+                } finally {
+                    if(!wakeLock.isHeld()) {
+                        wakeLock.acquire();
+                    }
+                    listener.releaseWakeLock();
+                    sensorManager.unregisterListener();
+                }
+            }
+        };
+        return new TestSensorOperation(environment, executor);
+    }
+
+    /**
      * Creates an operation that will wait for a given amount of time to collect events.
      *
      * @param environment The test environment.
@@ -269,7 +344,7 @@
                     sensorManager.registerListener(listener);
                     SensorCtsHelper.sleep(duration, timeUnit);
                     CountDownLatch latch = sensorManager.requestFlush();
-                    listener.waitForFlushComplete(latch);
+                    listener.waitForFlushComplete(latch, true);
                 } finally {
                     sensorManager.unregisterListener();
                 }
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/BatchArrivalVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/BatchArrivalVerification.java
new file mode 100644
index 0000000..5e50c3a
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/BatchArrivalVerification.java
@@ -0,0 +1,139 @@
+
+package android.hardware.cts.helpers.sensorverification;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import android.hardware.Sensor;
+import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.TestSensorEnvironment;
+import android.hardware.cts.helpers.TestSensorEvent;
+import android.hardware.cts.helpers.sensorverification.AbstractSensorVerification.IndexedEventPair;
+import android.os.SystemClock;
+import android.provider.Settings.System;
+
+import junit.framework.Assert;
+
+/**
+ * A {@link ISensorVerification} which verifies that there are no missing events. This is done by
+ * checking the last received sensor timestamp and checking that it is within 1.8 * the expected
+ * period.
+ */
+public class BatchArrivalVerification extends AbstractSensorVerification {
+    public static final String PASSED_KEY = "missing_event_passed";
+
+    // Batch arrival tolerance is 5 seconds.
+    private static final int BATCH_ARRIVAL_TOLERANCE_US = 5000000;
+
+    // Number of indices to print in assert message before truncating
+    private static final int TRUNCATE_MESSAGE_LENGTH = 3;
+
+    // Number of events to truncate (discard) from the initial events received
+    private static final int TRUNCATE_EVENTS_COUNT = 100;
+
+    private final long mExpectedBatchArrivalTimeUs;
+
+    private final List<IndexedEventPair> mFailures = new LinkedList<IndexedEventPair>();
+    private TestSensorEvent mFirstEvent = null;
+    private int mIndex = 0;
+
+    /**
+     * Construct a {@link EventGapVerification}
+     *
+     * @param expectedDelayUs the expected period in us.
+     */
+    public BatchArrivalVerification(long expectedBatchArrivalTimeUs) {
+         mExpectedBatchArrivalTimeUs = expectedBatchArrivalTimeUs;
+    }
+
+    /**
+     * Get the default {@link EventGapVerification}.
+     *
+     * @param environment the test environment
+     * @return the verification or null if the verification is not a continuous mode sensor.
+     */
+    public static BatchArrivalVerification getDefault(TestSensorEnvironment environment) {
+        if (environment.getSensor().getReportingMode() != Sensor.REPORTING_MODE_CONTINUOUS) {
+            return null;
+        }
+        long fifoMaxEventCount = environment.getSensor().getFifoMaxEventCount();
+        int maximumExpectedSamplingPeriodUs = environment.getMaximumExpectedSamplingPeriodUs();
+        long reportLatencyUs = environment.getMaxReportLatencyUs();
+        if (fifoMaxEventCount > 0 && maximumExpectedSamplingPeriodUs != Integer.MAX_VALUE) {
+            long fifoBasedReportLatencyUs =
+                    fifoMaxEventCount * maximumExpectedSamplingPeriodUs;
+            // If the device goes into suspend mode during the test and the sensor under test is
+            // a non wake-up sensor, the FIFO will keep overwriting itself and the reportLatency
+            // of each event will be equal to the time it takes to fill up the FIFO.
+            if (environment.isDeviceSuspendTest() && !environment.getSensor().isWakeUpSensor()) {
+                reportLatencyUs = fifoBasedReportLatencyUs;
+            } else {
+                // In this case the sensor under test is either a wake-up sensor OR it
+                // is a non wake-up sensor but the device does not go into suspend.
+                // So the expected delay of a sensor_event is the minimum of the
+                // fifoBasedReportLatencyUs and the requested latency by the application.
+                reportLatencyUs = Math.min(reportLatencyUs, fifoBasedReportLatencyUs);
+            }
+        }
+        long expectedBatchArrivalTimeUs = reportLatencyUs + SystemClock.elapsedRealtime() * 1000;
+        return new BatchArrivalVerification(expectedBatchArrivalTimeUs);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void verify(TestSensorEnvironment environment, SensorStats stats) {
+        final int count = mFailures.size();
+        stats.addValue(PASSED_KEY, count == 0);
+        stats.addValue(SensorStats.DELAYED_BATCH_DELIVERY, count);
+
+        if (count > 0) {
+            StringBuilder sb = new StringBuilder();
+            sb.append(count).append(" batch delayed: ");
+            for (int i = 0; i < Math.min(count, TRUNCATE_MESSAGE_LENGTH); i++) {
+                IndexedEventPair info = mFailures.get(i);
+                sb.append(String.format("expectedBatchArrival=%dms actualBatchArrivalTime=%dms "+
+                                        "diff=%dms tolerance=%dms",
+                                         (mExpectedBatchArrivalTimeUs)/1000,
+                                         info.event.receivedTimestamp/(1000 * 1000),
+                                         (mExpectedBatchArrivalTimeUs -
+                                          info.event.receivedTimestamp/1000)/1000,
+                                         BATCH_ARRIVAL_TOLERANCE_US/1000)
+
+                          );
+
+            }
+            if (count > TRUNCATE_MESSAGE_LENGTH) {
+                sb.append(count - TRUNCATE_MESSAGE_LENGTH).append(" more; ");
+            }
+            Assert.fail(sb.toString());
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public BatchArrivalVerification clone() {
+        return new BatchArrivalVerification(mExpectedBatchArrivalTimeUs);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void addSensorEventInternal(TestSensorEvent event) {
+        if (mFirstEvent == null) {
+            mFirstEvent = event;
+        }
+        if (mIndex == 1) {
+            if (Math.abs(mFirstEvent.receivedTimestamp/1000 - mExpectedBatchArrivalTimeUs) >
+                BATCH_ARRIVAL_TOLERANCE_US) {
+                mFailures.add(new IndexedEventPair(1, mFirstEvent, null));
+            }
+        }
+        ++mIndex;
+    }
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventTimestampSynchronizationVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventTimestampSynchronizationVerification.java
index a90725f..3af3f03 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventTimestampSynchronizationVerification.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventTimestampSynchronizationVerification.java
@@ -75,6 +75,16 @@
                     fifoMaxEventCount * maximumExpectedSamplingPeriodUs;
             reportLatencyUs = Math.min(reportLatencyUs, fifoBasedReportLatencyUs) +
                 (long)(2.5 * maximumExpectedSamplingPeriodUs);
+            // of each event will be equal to the time it takes to fill up the FIFO.
+            if (environment.isDeviceSuspendTest() && !environment.getSensor().isWakeUpSensor()) {
+                reportLatencyUs = fifoBasedReportLatencyUs;
+            } else {
+                // In this case the sensor under test is either a wake-up sensor OR it
+                // is a non wake-up sensor but the device does not go into suspend.
+                // So the expected delay of a sensor_event is the minimum of the
+                // fifoBasedReportLatencyUs and the requested latency by the application.
+                reportLatencyUs = Math.min(reportLatencyUs, fifoBasedReportLatencyUs);
+            }
         }
         long expectedSyncLatencyNs = TimeUnit.MICROSECONDS.toNanos(reportLatencyUs);
         return new EventTimestampSynchronizationVerification(DEFAULT_THRESHOLD_NS,
diff --git a/tests/tests/keystore/res/raw/ec_key2_cert.der b/tests/tests/keystore/res/raw/ec_key2_cert.der
new file mode 100644
index 0000000..576d8f9
--- /dev/null
+++ b/tests/tests/keystore/res/raw/ec_key2_cert.der
Binary files differ
diff --git a/tests/tests/keystore/res/raw/ec_key2_pkcs8.der b/tests/tests/keystore/res/raw/ec_key2_pkcs8.der
new file mode 100644
index 0000000..26f4f05
--- /dev/null
+++ b/tests/tests/keystore/res/raw/ec_key2_pkcs8.der
Binary files differ
diff --git a/tests/tests/keystore/res/raw/rsa_key2_cert.der b/tests/tests/keystore/res/raw/rsa_key2_cert.der
new file mode 100644
index 0000000..b00495c
--- /dev/null
+++ b/tests/tests/keystore/res/raw/rsa_key2_cert.der
Binary files differ
diff --git a/tests/tests/keystore/res/raw/rsa_key2_pkcs8.der b/tests/tests/keystore/res/raw/rsa_key2_pkcs8.der
new file mode 100644
index 0000000..c687f7d
--- /dev/null
+++ b/tests/tests/keystore/res/raw/rsa_key2_pkcs8.der
Binary files differ
diff --git a/tests/tests/keystore/src/android/keystore/cts/AES128CBCNoPaddingCipherTest.java b/tests/tests/keystore/src/android/keystore/cts/AES128CBCNoPaddingCipherTest.java
new file mode 100644
index 0000000..e56049c
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/AES128CBCNoPaddingCipherTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+public class AES128CBCNoPaddingCipherTest extends AESCBCNoPaddingCipherTestBase {
+
+    private static final byte[] KAT_KEY = HexEncoding.decode("7E3D723C09A9852B24F584F9D916F6A8");
+    private static final byte[] KAT_IV = HexEncoding.decode("944AE274D983892EADE422274858A96A");
+    private static final byte[] KAT_PLAINTEXT = HexEncoding.decode(
+            "044E15899A080AADEB6778F64323B64D2CBCBADB338DF93B9AC459D4F41029809FFF37081C22EF278F896A"
+            + "B213A2A631");
+    private static final byte[] KAT_CIPHERTEXT = HexEncoding.decode(
+            "B419293FCBD686F2913D1CF947E510D42FAFEDE5593C98AFD6AEE272596A56FE42C22F2A5E3B6A02BA9D8D"
+            + "0DE1E9A810");
+
+    @Override
+    protected byte[] getKatKey() {
+        return KAT_KEY.clone();
+    }
+
+    @Override
+    protected byte[] getKatIv() {
+        return KAT_IV.clone();
+    }
+
+    @Override
+    protected byte[] getKatPlaintext() {
+        return KAT_PLAINTEXT.clone();
+    }
+
+    @Override
+    protected byte[] getKatCiphertext() {
+        return KAT_CIPHERTEXT.clone();
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/AES128CBCPKCS7PaddingCipherTest.java b/tests/tests/keystore/src/android/keystore/cts/AES128CBCPKCS7PaddingCipherTest.java
new file mode 100644
index 0000000..d8254c1
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/AES128CBCPKCS7PaddingCipherTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+public class AES128CBCPKCS7PaddingCipherTest extends AESCBCPKCS7PaddingCipherTestBase {
+
+    private static final byte[] KAT_KEY = HexEncoding.decode("F16E698472578E919D92806262C5169F");
+    private static final byte[] KAT_IV = HexEncoding.decode("EF743540F8421ACA128A3247521F3E7D");
+    private static final byte[] KAT_PLAINTEXT = HexEncoding.decode(
+            "5BEBF33569D90BF5E853814E12E7C7AA5758013F755773E29F4A25EC26EEB765F7F2DC251F7DC62AEFCA1E"
+            + "8A5A11A1DCD44F0BD8FB593A5AE3");
+    private static final byte[] KAT_CIPHERTEXT = HexEncoding.decode(
+            "3197CF6DB9466188B5FED375329324EE7D6092A8C0E41DFAF49E3724271427896D56A6243C0D59D6639722"
+            + "AF93CD53449BDDABF9C5F153EBDBFED9ED98C8CC37");
+
+    @Override
+    protected byte[] getKatKey() {
+        return KAT_KEY.clone();
+    }
+
+    @Override
+    protected byte[] getKatIv() {
+        return KAT_IV.clone();
+    }
+
+    @Override
+    protected byte[] getKatPlaintext() {
+        return KAT_PLAINTEXT.clone();
+    }
+
+    @Override
+    protected byte[] getKatCiphertext() {
+        return KAT_CIPHERTEXT.clone();
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/AES128CTRNoPaddingCipherTest.java b/tests/tests/keystore/src/android/keystore/cts/AES128CTRNoPaddingCipherTest.java
new file mode 100644
index 0000000..7ffca13
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/AES128CTRNoPaddingCipherTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+public class AES128CTRNoPaddingCipherTest extends AESCTRNoPaddingCipherTestBase {
+
+    private static final byte[] KAT_KEY = HexEncoding.decode("4713a7b2f93efe809b42ecc45213ef9f");
+    private static final byte[] KAT_IV = HexEncoding.decode("ebfa19b0ebf3d57feabd4c4bd04bea01");
+    private static final byte[] KAT_PLAINTEXT = HexEncoding.decode(
+            "6d2c07e1fc86f99c6e2a8f6567828b4262a9c23d0f3ed8ab32482283c79796f0adba1bcd3736084996452a"
+            +"917fae98005aebe61f9e91c3");
+    private static final byte[] KAT_CIPHERTEXT = HexEncoding.decode(
+            "345deb1d67b95e600e05cad4c32ec381aadb3e2c1ec7e0fb956dc38e6860cf0553535566e1b12fa9f87d29"
+            + "266ca26df427233df035df28");
+
+    @Override
+    protected byte[] getKatKey() {
+        return KAT_KEY.clone();
+    }
+
+    @Override
+    protected byte[] getKatIv() {
+        return KAT_IV.clone();
+    }
+
+    @Override
+    protected byte[] getKatPlaintext() {
+        return KAT_PLAINTEXT.clone();
+    }
+
+    @Override
+    protected byte[] getKatCiphertext() {
+        return KAT_CIPHERTEXT.clone();
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/AES128ECBNoPaddingCipherTest.java b/tests/tests/keystore/src/android/keystore/cts/AES128ECBNoPaddingCipherTest.java
new file mode 100644
index 0000000..100700c
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/AES128ECBNoPaddingCipherTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+public class AES128ECBNoPaddingCipherTest extends AESECBNoPaddingCipherTestBase {
+
+    private static final byte[] KAT_KEY = HexEncoding.decode("7DA2467F068854B3CB36E5C333A16619");
+    private static final byte[] KAT_PLAINTEXT = HexEncoding.decode(
+            "9A07C9575AD9CE209DF9F3953965CEBE8208587C7AE575A1904BF25048946D7B6168A9A27BCE554BEA94EF"
+            + "26E6C742A0");
+    private static final byte[] KAT_CIPHERTEXT = HexEncoding.decode(
+            "8C47E49420FC92AC4CA2C601BC3F8AC31D01B260B7B849F2B8EEDFFFED8F36C31CBDA0D22F95C9C2A48C34"
+            + "7E8C77AC82");
+
+    @Override
+    protected byte[] getKatKey() {
+        return KAT_KEY.clone();
+    }
+
+    @Override
+    protected byte[] getKatIv() {
+        return null;
+    }
+
+    @Override
+    protected byte[] getKatPlaintext() {
+        return KAT_PLAINTEXT.clone();
+    }
+
+    @Override
+    protected byte[] getKatCiphertext() {
+        return KAT_CIPHERTEXT.clone();
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/AES128ECBPKCS7PaddingCipherTest.java b/tests/tests/keystore/src/android/keystore/cts/AES128ECBPKCS7PaddingCipherTest.java
new file mode 100644
index 0000000..c834ddf
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/AES128ECBPKCS7PaddingCipherTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+public class AES128ECBPKCS7PaddingCipherTest extends AESECBPKCS7PaddingCipherTestBase {
+
+    private static final byte[] KAT_KEY = HexEncoding.decode("C3BE04BCCB3D99B85290F113FE7AF194");
+    private static final byte[] KAT_PLAINTEXT = HexEncoding.decode(
+            "348C213FD8DF3F990C20C5ACBF07B34B6264AE245784A5A6176DBFB1C2E7DD27E52CC92B8EEE40614F05B5"
+            + "07B355F6354A2705BD86");
+    private static final byte[] KAT_CIPHERTEXT = HexEncoding.decode(
+            "07CD05C41FEDEDDC5DB4B3E35E676153184A119AA4DFDDC290616F1FA600931DE6BEA9BDB90D1D73389994"
+            + "6F8C8E5C0C4383F99F5D88E27F3EBC0C6E52759ED3");
+
+    @Override
+    protected byte[] getKatKey() {
+        return KAT_KEY.clone();
+    }
+
+    @Override
+    protected byte[] getKatIv() {
+        return null;
+    }
+
+    @Override
+    protected byte[] getKatPlaintext() {
+        return KAT_PLAINTEXT.clone();
+    }
+
+    @Override
+    protected byte[] getKatCiphertext() {
+        return KAT_CIPHERTEXT.clone();
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/AES128GCMNoPaddingCipherTest.java b/tests/tests/keystore/src/android/keystore/cts/AES128GCMNoPaddingCipherTest.java
new file mode 100644
index 0000000..6ae13ce
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/AES128GCMNoPaddingCipherTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+public class AES128GCMNoPaddingCipherTest extends AESGCMNoPaddingCipherTestBase {
+
+    private static final byte[] KAT_KEY = HexEncoding.decode("ba76354f0aed6e8d91f45c4ff5a062db");
+    private static final byte[] KAT_IV = HexEncoding.decode("b79437ae08ff355d7d8a4d0f");
+    private static final byte[] KAT_PLAINTEXT = HexEncoding.decode(
+            "6d7596a8fd56ceaec61de7940984b7736fec44f572afc3c8952e4dc6541e2bc6a702c440a37610989543f6"
+            + "3fedb047ca2173bc18581944");
+    private static final byte[] KAT_CIPHERTEXT = HexEncoding.decode(
+            "b3f6799e8f9326f2df1e80fcd2cb16d78c9dc7cc14bb677862dc6c639b3a6338d24b312d3989e5920b5dbf"
+            + "c976765efbfe57bb385940a7a43bdf05bddae3c9d6a2fbbdfcc0cba0");
+
+    @Override
+    protected byte[] getKatKey() {
+        return KAT_KEY.clone();
+    }
+
+    @Override
+    protected byte[] getKatIv() {
+        return KAT_IV.clone();
+    }
+
+    @Override
+    protected byte[] getKatPlaintext() {
+        return KAT_PLAINTEXT.clone();
+    }
+
+    @Override
+    protected byte[] getKatCiphertext() {
+        return KAT_CIPHERTEXT.clone();
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/AESCBCCipherTestBase.java b/tests/tests/keystore/src/android/keystore/cts/AESCBCCipherTestBase.java
new file mode 100644
index 0000000..8f1aed69
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/AESCBCCipherTestBase.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+import java.security.AlgorithmParameters;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.IvParameterSpec;
+
+abstract class AESCBCCipherTestBase extends BlockCipherTestBase {
+
+    @Override
+    protected boolean isStreamCipher() {
+        return false;
+    }
+
+    @Override
+    protected boolean isAuthenticatedCipher() {
+        return false;
+    }
+
+    @Override
+    protected int getKatAuthenticationTagLengthBytes() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected int getBlockSize() {
+        return 16;
+    }
+
+    @Override
+    protected AlgorithmParameterSpec getKatAlgorithmParameterSpec() {
+        return new IvParameterSpec(getKatIv());
+    }
+
+    @Override
+    protected byte[] getIv(AlgorithmParameters params) throws InvalidParameterSpecException {
+        IvParameterSpec spec = params.getParameterSpec(IvParameterSpec.class);
+        return spec.getIV();
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/AESCBCNoPaddingCipherTestBase.java b/tests/tests/keystore/src/android/keystore/cts/AESCBCNoPaddingCipherTestBase.java
new file mode 100644
index 0000000..8e51d04
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/AESCBCNoPaddingCipherTestBase.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+abstract class AESCBCNoPaddingCipherTestBase extends AESCBCCipherTestBase {
+
+    @Override
+    protected String getTransformation() {
+        return "AES/CBC/NoPadding";
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/AESCBCPKS7PaddingCipherTestBase.java b/tests/tests/keystore/src/android/keystore/cts/AESCBCPKS7PaddingCipherTestBase.java
new file mode 100644
index 0000000..bd2c5bd
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/AESCBCPKS7PaddingCipherTestBase.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+abstract class AESCBCPKCS7PaddingCipherTestBase extends AESCBCCipherTestBase {
+
+    @Override
+    protected String getTransformation() {
+        return "AES/CBC/PKCS7Padding";
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/AESCTRCipherTestBase.java b/tests/tests/keystore/src/android/keystore/cts/AESCTRCipherTestBase.java
new file mode 100644
index 0000000..8bf6ac1
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/AESCTRCipherTestBase.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+import java.security.AlgorithmParameters;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.IvParameterSpec;
+
+abstract class AESCTRCipherTestBase extends BlockCipherTestBase {
+
+    @Override
+    protected boolean isStreamCipher() {
+        return true;
+    }
+
+    @Override
+    protected boolean isAuthenticatedCipher() {
+        return false;
+    }
+
+    @Override
+    protected int getKatAuthenticationTagLengthBytes() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected int getBlockSize() {
+        return 16;
+    }
+
+    @Override
+    protected AlgorithmParameterSpec getKatAlgorithmParameterSpec() {
+        return new IvParameterSpec(getKatIv());
+    }
+
+    @Override
+    protected byte[] getIv(AlgorithmParameters params) throws InvalidParameterSpecException {
+        IvParameterSpec spec = params.getParameterSpec(IvParameterSpec.class);
+        return spec.getIV();
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/AESCTRNoPaddingCipherTestBase.java b/tests/tests/keystore/src/android/keystore/cts/AESCTRNoPaddingCipherTestBase.java
new file mode 100644
index 0000000..e504310
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/AESCTRNoPaddingCipherTestBase.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+abstract class AESCTRNoPaddingCipherTestBase extends AESCTRCipherTestBase {
+    @Override
+    protected String getTransformation() {
+        return "AES/CTR/NoPadding";
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/AESECBCipherTestBase.java b/tests/tests/keystore/src/android/keystore/cts/AESECBCipherTestBase.java
new file mode 100644
index 0000000..5ecf22f
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/AESECBCipherTestBase.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+import java.security.AlgorithmParameters;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+abstract class AESECBCipherTestBase extends BlockCipherTestBase {
+
+    @Override
+    protected boolean isStreamCipher() {
+        return false;
+    }
+
+    @Override
+    protected boolean isAuthenticatedCipher() {
+        return false;
+    }
+
+    @Override
+    protected int getKatAuthenticationTagLengthBytes() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected int getBlockSize() {
+        return 16;
+    }
+
+    @Override
+    protected AlgorithmParameterSpec getKatAlgorithmParameterSpec() {
+        return null;
+    }
+
+    @Override
+    protected byte[] getIv(AlgorithmParameters params) throws InvalidParameterSpecException {
+        if (params != null) {
+            fail("ECB does not use IV");
+        }
+        return null;
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/AESECBNoPaddingCipherTestBase.java b/tests/tests/keystore/src/android/keystore/cts/AESECBNoPaddingCipherTestBase.java
new file mode 100644
index 0000000..8c38015
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/AESECBNoPaddingCipherTestBase.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+abstract class AESECBNoPaddingCipherTestBase extends AESECBCipherTestBase {
+    @Override
+    protected String getTransformation() {
+        return "AES/ECB/NoPadding";
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/AESECBPKCS7PaddingCipherTestBase.java b/tests/tests/keystore/src/android/keystore/cts/AESECBPKCS7PaddingCipherTestBase.java
new file mode 100644
index 0000000..67e659c
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/AESECBPKCS7PaddingCipherTestBase.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+abstract class AESECBPKCS7PaddingCipherTestBase extends AESECBCipherTestBase {
+    @Override
+    protected String getTransformation() {
+        return "AES/ECB/PKCS7Padding";
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/AESGCMCipherTestBase.java b/tests/tests/keystore/src/android/keystore/cts/AESGCMCipherTestBase.java
new file mode 100644
index 0000000..d901674
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/AESGCMCipherTestBase.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+import java.security.AlgorithmParameters;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.GCMParameterSpec;
+
+abstract class AESGCMCipherTestBase extends BlockCipherTestBase {
+
+    @Override
+    protected boolean isStreamCipher() {
+        return true;
+    }
+
+    @Override
+    protected boolean isAuthenticatedCipher() {
+        return true;
+    }
+
+    @Override
+    protected int getKatAuthenticationTagLengthBytes() {
+        return getKatCiphertext().length - getKatPlaintext().length;
+    }
+
+    @Override
+    protected int getBlockSize() {
+        return 16;
+    }
+
+    @Override
+    protected AlgorithmParameterSpec getKatAlgorithmParameterSpec() {
+        return new GCMParameterSpec(getKatAuthenticationTagLengthBytes() * 8, getKatIv());
+    }
+
+    @Override
+    protected byte[] getIv(AlgorithmParameters params) throws InvalidParameterSpecException {
+        GCMParameterSpec spec = params.getParameterSpec(GCMParameterSpec.class);
+        return spec.getIV();
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/AESGCMNoPaddingCipherTestBase.java b/tests/tests/keystore/src/android/keystore/cts/AESGCMNoPaddingCipherTestBase.java
new file mode 100644
index 0000000..c29e644
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/AESGCMNoPaddingCipherTestBase.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+abstract class AESGCMNoPaddingCipherTestBase extends AESGCMCipherTestBase {
+    @Override
+    protected String getTransformation() {
+        return "AES/GCM/NoPadding";
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java b/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
index 11769ad..6b81285 100644
--- a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
@@ -18,12 +18,19 @@
 
 import android.security.KeyPairGeneratorSpec;
 import android.security.KeyStoreParameter;
+import android.security.keystore.KeyProperties;
+import android.security.keystore.KeyProtection;
 import android.test.AndroidTestCase;
+import android.test.MoreAsserts;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import com.android.cts.keystore.R;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.OutputStream;
 import java.math.BigInteger;
+import java.security.AlgorithmParameters;
 import java.security.Key;
 import java.security.KeyFactory;
 import java.security.KeyPairGenerator;
@@ -52,7 +59,9 @@
 
 import javax.crypto.BadPaddingException;
 import javax.crypto.Cipher;
+import javax.crypto.Mac;
 import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
 import javax.security.auth.x500.X500Principal;
 
@@ -706,6 +715,8 @@
 
     @Override
     protected void setUp() throws Exception {
+        super.setUp();
+
         // Wipe any existing entries in the KeyStore
         KeyStore ksTemp = KeyStore.getInstance("AndroidKeyStore");
         ksTemp.load(null, null);
@@ -719,6 +730,21 @@
         mKeyStore = KeyStore.getInstance("AndroidKeyStore");
     }
 
+    @Override
+    protected void tearDown() throws Exception {
+        try {
+            KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+            keyStore.load(null, null);
+            Enumeration<String> aliases = keyStore.aliases();
+            while (aliases.hasMoreElements()) {
+                String alias = aliases.nextElement();
+                keyStore.deleteEntry(alias);
+            }
+        } finally {
+            super.tearDown();
+        }
+    }
+
     private PrivateKey generatePrivateKey(String keyType, byte[] fakeKey1) throws Exception {
         KeyFactory kf = KeyFactory.getInstance(keyType);
         return kf.generatePrivate(new PKCS8EncodedKeySpec(fakeKey1));
@@ -1980,4 +2006,283 @@
         Signature.getInstance("SHA256withECDSA").initVerify(publicKey);
         Signature.getInstance("NONEwithECDSA").initVerify(publicKey);
     }
+
+    private static final int MIN_SUPPORTED_KEY_COUNT = 10000;
+
+    @LargeTest
+    public void testKeyStore_LargeNumberOfKeysSupported_RSA() throws Exception {
+        // This test imports key1, then lots of other keys, then key2, and then confirms that
+        // key1 and key2 backed by Android Keystore work fine. The assumption is that if the
+        // underlying implementation has a limit on the number of keys, it'll either delete the
+        // oldest key (key1), or will refuse to add keys (key2).
+
+        Certificate cert1 = TestUtils.getRawResX509Certificate(getContext(), R.raw.rsa_key1_cert);
+        PrivateKey privateKey1 = TestUtils.getRawResPrivateKey(getContext(), R.raw.rsa_key1_pkcs8);
+        String entryName1 = "test0";
+
+        Certificate cert2 = TestUtils.getRawResX509Certificate(getContext(), R.raw.rsa_key2_cert);
+        PrivateKey privateKey2 = TestUtils.getRawResPrivateKey(getContext(), R.raw.rsa_key2_pkcs8);
+        String entryName2 = "test" + MIN_SUPPORTED_KEY_COUNT;
+
+        Certificate cert3 = generateCertificate(FAKE_RSA_USER_1);
+        PrivateKey privateKey3 = generatePrivateKey("RSA", FAKE_RSA_KEY_1);
+
+        mKeyStore.load(null);
+        try {
+            KeyProtection protectionParams = new KeyProtection.Builder(
+                    KeyProperties.PURPOSE_SIGN)
+                    .setDigests(KeyProperties.DIGEST_SHA256)
+                    .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
+                    .build();
+            mKeyStore.setEntry(entryName1,
+                    new KeyStore.PrivateKeyEntry(privateKey1, new Certificate[] {cert1}),
+                    protectionParams);
+
+            // Import key3 many of times, under different aliases.
+            for (int i = 1; i < MIN_SUPPORTED_KEY_COUNT; i++) {
+                String entryAlias = "test" + i;
+                try {
+                    mKeyStore.setEntry(entryAlias,
+                            new KeyStore.PrivateKeyEntry(privateKey3, new Certificate[] {cert3}),
+                            protectionParams);
+                } catch (Throwable e) {
+                    throw new RuntimeException("Entry " + entryAlias + " import failed", e);
+                }
+            }
+
+            mKeyStore.setEntry(entryName2,
+                    new KeyStore.PrivateKeyEntry(privateKey2, new Certificate[] {cert2}),
+                    protectionParams);
+            PrivateKey keystorePrivateKey2 = (PrivateKey) mKeyStore.getKey(entryName2, null);
+            PrivateKey keystorePrivateKey1 = (PrivateKey) mKeyStore.getKey(entryName1, null);
+
+            byte[] message = "This is a test".getBytes("UTF-8");
+
+            Signature sig = Signature.getInstance("SHA256withRSA");
+            sig.initSign(keystorePrivateKey1);
+            sig.update(message);
+            byte[] signature = sig.sign();
+            sig = Signature.getInstance(sig.getAlgorithm());
+            sig.initVerify(cert1.getPublicKey());
+            sig.update(message);
+            assertTrue(sig.verify(signature));
+
+            sig = Signature.getInstance(sig.getAlgorithm());
+            sig.initSign(keystorePrivateKey2);
+            sig.update(message);
+            signature = sig.sign();
+            sig = Signature.getInstance(sig.getAlgorithm());
+            sig.initVerify(cert2.getPublicKey());
+            sig.update(message);
+            assertTrue(sig.verify(signature));
+        } finally {
+            // Clean up Keystore without using KeyStore.aliases() which can't handle this many
+            // entries.
+            for (int i = 0; i <= MIN_SUPPORTED_KEY_COUNT; i++) {
+                mKeyStore.deleteEntry("test" + i);
+            }
+        }
+    }
+
+    @LargeTest
+    public void testKeyStore_LargeNumberOfKeysSupported_EC() throws Exception {
+        // This test imports key1, then lots of other keys, then key2, and then confirms that
+        // key1 and key2 backed by Android Keystore work fine. The assumption is that if the
+        // underlying implementation has a limit on the number of keys, it'll either delete the
+        // oldest key (key1), or will refuse to add keys (key2).
+
+        Certificate cert1 = TestUtils.getRawResX509Certificate(getContext(), R.raw.ec_key1_cert);
+        PrivateKey privateKey1 = TestUtils.getRawResPrivateKey(getContext(), R.raw.ec_key1_pkcs8);
+        String entryName1 = "test0";
+
+        Certificate cert2 = TestUtils.getRawResX509Certificate(getContext(), R.raw.ec_key2_cert);
+        PrivateKey privateKey2 = TestUtils.getRawResPrivateKey(getContext(), R.raw.ec_key2_pkcs8);
+        String entryName2 = "test" + MIN_SUPPORTED_KEY_COUNT;
+
+        Certificate cert3 = generateCertificate(FAKE_EC_USER_1);
+        PrivateKey privateKey3 = generatePrivateKey("EC", FAKE_EC_KEY_1);
+
+        mKeyStore.load(null);
+        try {
+            KeyProtection protectionParams = new KeyProtection.Builder(
+                    KeyProperties.PURPOSE_SIGN)
+                    .setDigests(KeyProperties.DIGEST_SHA256)
+                    .build();
+            mKeyStore.setEntry(entryName1,
+                    new KeyStore.PrivateKeyEntry(privateKey1, new Certificate[] {cert1}),
+                    protectionParams);
+
+            // Import key3 many of times, under different aliases.
+            for (int i = 1; i < MIN_SUPPORTED_KEY_COUNT; i++) {
+                String entryAlias = "test" + i;
+                try {
+                    mKeyStore.setEntry(entryAlias,
+                            new KeyStore.PrivateKeyEntry(privateKey3, new Certificate[] {cert3}),
+                            protectionParams);
+                } catch (Throwable e) {
+                    throw new RuntimeException("Entry " + entryAlias + " import failed", e);
+                }
+            }
+
+            mKeyStore.setEntry(entryName2,
+                    new KeyStore.PrivateKeyEntry(privateKey2, new Certificate[] {cert2}),
+                    protectionParams);
+            PrivateKey keystorePrivateKey2 = (PrivateKey) mKeyStore.getKey(entryName2, null);
+            PrivateKey keystorePrivateKey1 = (PrivateKey) mKeyStore.getKey(entryName1, null);
+
+            byte[] message = "This is a test".getBytes("UTF-8");
+
+            Signature sig = Signature.getInstance("SHA256withECDSA");
+            sig.initSign(keystorePrivateKey1);
+            sig.update(message);
+            byte[] signature = sig.sign();
+            sig = Signature.getInstance(sig.getAlgorithm());
+            sig.initVerify(cert1.getPublicKey());
+            sig.update(message);
+            assertTrue(sig.verify(signature));
+
+            sig = Signature.getInstance(sig.getAlgorithm());
+            sig.initSign(keystorePrivateKey2);
+            sig.update(message);
+            signature = sig.sign();
+            sig = Signature.getInstance(sig.getAlgorithm());
+            sig.initVerify(cert2.getPublicKey());
+            sig.update(message);
+            assertTrue(sig.verify(signature));
+        } finally {
+            // Clean up Keystore without using KeyStore.aliases() which can't handle this many
+            // entries.
+            for (int i = 0; i <= MIN_SUPPORTED_KEY_COUNT; i++) {
+                mKeyStore.deleteEntry("test" + i);
+            }
+        }
+    }
+
+    @LargeTest
+    public void testKeyStore_LargeNumberOfKeysSupported_AES() throws Exception {
+        // This test imports key1, then lots of other keys, then key2, and then confirms that
+        // key1 and key2 backed by Android Keystore work fine. The assumption is that if the
+        // underlying implementation has a limit on the number of keys, it'll either delete the
+        // oldest key (key1), or will refuse to add keys (key2).
+
+        SecretKey key1 =
+                new SecretKeySpec(HexEncoding.decode("010203040506070809fafbfcfdfeffcc"), "AES");
+        String entryName1 = "test0";
+
+        SecretKey key2 =
+                new SecretKeySpec(HexEncoding.decode("808182838485868788897a7b7c7d7e7f"), "AES");
+        String entryName2 = "test" + MIN_SUPPORTED_KEY_COUNT;
+
+        SecretKey key3 =
+                new SecretKeySpec(HexEncoding.decode("33333333333333333333777777777777"), "AES");
+
+        mKeyStore.load(null);
+        try {
+            KeyProtection protectionParams = new KeyProtection.Builder(
+                    KeyProperties.PURPOSE_ENCRYPT)
+                    .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                    .build();
+            mKeyStore.setEntry(entryName1, new KeyStore.SecretKeyEntry(key1), protectionParams);
+
+            // Import key3 many of times, under different aliases.
+            for (int i = 1; i < MIN_SUPPORTED_KEY_COUNT; i++) {
+                String entryAlias = "test" + i;
+                try {
+                    mKeyStore.setEntry(entryAlias, new KeyStore.SecretKeyEntry(key3), protectionParams);
+                } catch (Throwable e) {
+                    throw new RuntimeException("Entry " + entryAlias + " import failed", e);
+                }
+            }
+
+            mKeyStore.setEntry(entryName2, new KeyStore.SecretKeyEntry(key2), protectionParams);
+            SecretKey keystoreKey2 = (SecretKey) mKeyStore.getKey(entryName2, null);
+            SecretKey keystoreKey1 = (SecretKey) mKeyStore.getKey(entryName1, null);
+
+            byte[] plaintext = "This is a test".getBytes("UTF-8");
+            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+            cipher.init(Cipher.ENCRYPT_MODE, keystoreKey1);
+            byte[] ciphertext = cipher.doFinal(plaintext);
+            AlgorithmParameters cipherParams = cipher.getParameters();
+            cipher = Cipher.getInstance(cipher.getAlgorithm());
+            cipher.init(Cipher.DECRYPT_MODE, key1, cipherParams);
+            MoreAsserts.assertEquals(plaintext, cipher.doFinal(ciphertext));
+
+            cipher = Cipher.getInstance(cipher.getAlgorithm());
+            cipher.init(Cipher.ENCRYPT_MODE, keystoreKey2);
+            ciphertext = cipher.doFinal(plaintext);
+            cipherParams = cipher.getParameters();
+            cipher = Cipher.getInstance(cipher.getAlgorithm());
+            cipher.init(Cipher.DECRYPT_MODE, key2, cipherParams);
+            MoreAsserts.assertEquals(plaintext, cipher.doFinal(ciphertext));
+        } finally {
+            // Clean up Keystore without using KeyStore.aliases() which can't handle this many
+            // entries.
+            for (int i = 0; i <= MIN_SUPPORTED_KEY_COUNT; i++) {
+                mKeyStore.deleteEntry("test" + i);
+            }
+        }
+    }
+
+    @LargeTest
+    public void testKeyStore_LargeNumberOfKeysSupported_HMAC() throws Exception {
+        // This test imports key1, then lots of other keys, then key2, and then confirms that
+        // key1 and key2 backed by Android Keystore work fine. The assumption is that if the
+        // underlying implementation has a limit on the number of keys, it'll either delete the
+        // oldest key (key1), or will refuse to add keys (key2).
+
+        SecretKey key1 = new SecretKeySpec(
+                HexEncoding.decode("010203040506070809fafbfcfdfeffcc"), "HmacSHA256");
+        String entryName1 = "test0";
+
+        SecretKey key2 = new SecretKeySpec(
+                HexEncoding.decode("808182838485868788897a7b7c7d7e7f"), "HmacSHA256");
+        String entryName2 = "test" + MIN_SUPPORTED_KEY_COUNT;
+
+        SecretKey key3 = new SecretKeySpec(
+                HexEncoding.decode("33333333333333333333777777777777"), "HmacSHA256");
+
+        mKeyStore.load(null);
+        try {
+            KeyProtection protectionParams = new KeyProtection.Builder(
+                    KeyProperties.PURPOSE_SIGN)
+                    .build();
+            mKeyStore.setEntry(entryName1, new KeyStore.SecretKeyEntry(key1), protectionParams);
+
+            // Import key3 many of times, under different aliases.
+            for (int i = 1; i < MIN_SUPPORTED_KEY_COUNT; i++) {
+                String entryAlias = "test" + i;
+                try {
+                    mKeyStore.setEntry(entryAlias, new KeyStore.SecretKeyEntry(key3), protectionParams);
+                } catch (Throwable e) {
+                    throw new RuntimeException("Entry " + entryAlias + " import failed", e);
+                }
+            }
+
+            mKeyStore.setEntry(entryName2, new KeyStore.SecretKeyEntry(key2), protectionParams);
+            SecretKey keystoreKey2 = (SecretKey) mKeyStore.getKey(entryName2, null);
+            SecretKey keystoreKey1 = (SecretKey) mKeyStore.getKey(entryName1, null);
+
+            byte[] message = "This is a test".getBytes("UTF-8");
+            Mac mac = Mac.getInstance(key1.getAlgorithm());
+            mac.init(keystoreKey1);
+            MoreAsserts.assertEquals(
+                    HexEncoding.decode(
+                            "905e36f5a175f4ca54ad56b860b46f6502f883a90628dca2d33a953fb7224eaf"),
+                    mac.doFinal(message));
+
+            mac = Mac.getInstance(key2.getAlgorithm());
+            mac.init(keystoreKey2);
+            MoreAsserts.assertEquals(
+                    HexEncoding.decode(
+                            "59b57e77e4e2cb36b5c7b84af198ac004327bc549de6931a1b5505372dd8c957"),
+                    mac.doFinal(message));
+        } finally {
+            // Clean up Keystore without using KeyStore.aliases() which can't handle this many
+            // entries.
+            for (int i = 0; i <= MIN_SUPPORTED_KEY_COUNT; i++) {
+                mKeyStore.deleteEntry("test" + i);
+            }
+        }
+    }
 }
diff --git a/tests/tests/keystore/src/android/keystore/cts/BlockCipherTestBase.java b/tests/tests/keystore/src/android/keystore/cts/BlockCipherTestBase.java
new file mode 100644
index 0000000..398d373
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/BlockCipherTestBase.java
@@ -0,0 +1,1575 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+import android.security.keystore.KeyProperties;
+import android.security.keystore.KeyProtection;
+import android.test.AndroidTestCase;
+
+import junit.framework.AssertionFailedError;
+
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.Locale;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.SecretKeySpec;
+
+abstract class BlockCipherTestBase extends AndroidTestCase {
+
+    private KeyStore mAndroidKeyStore;
+    private int mNextKeyId;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mAndroidKeyStore = KeyStore.getInstance("AndroidKeyStore");
+        mAndroidKeyStore.load(null);
+        for (Enumeration<String> e = mAndroidKeyStore.aliases(); e.hasMoreElements();) {
+            mAndroidKeyStore.deleteEntry(e.nextElement());
+        }
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        try {
+            for (Enumeration<String> e = mAndroidKeyStore.aliases(); e.hasMoreElements();) {
+                mAndroidKeyStore.deleteEntry(e.nextElement());
+            }
+        } finally {
+            super.tearDown();
+        }
+    }
+
+    protected abstract String getTransformation();
+    protected abstract int getBlockSize();
+
+    protected abstract byte[] getKatKey();
+    protected abstract byte[] getKatIv();
+    protected abstract AlgorithmParameterSpec getKatAlgorithmParameterSpec();
+    protected abstract byte[] getKatPlaintext();
+    protected abstract byte[] getKatCiphertext();
+    protected abstract int getKatAuthenticationTagLengthBytes();
+    protected abstract boolean isStreamCipher();
+    protected abstract boolean isAuthenticatedCipher();
+
+    protected abstract byte[] getIv(AlgorithmParameters params)
+            throws InvalidParameterSpecException;
+
+    private byte[] getKatInput(int opmode) {
+        switch (opmode) {
+            case Cipher.ENCRYPT_MODE:
+                return getKatPlaintext();
+            case Cipher.DECRYPT_MODE:
+                return getKatCiphertext();
+            default:
+                throw new IllegalArgumentException("Invalid opmode: " + opmode);
+        }
+    }
+
+    private byte[] getKatOutput(int opmode) {
+        switch (opmode) {
+            case Cipher.ENCRYPT_MODE:
+                return getKatCiphertext();
+            case Cipher.DECRYPT_MODE:
+                return getKatPlaintext();
+            default:
+                throw new IllegalArgumentException("Invalid opmode: " + opmode);
+        }
+    }
+
+    private Cipher mCipher;
+    private int mOpmode;
+
+    public void testGetAlgorithm() throws Exception {
+        createCipher();
+        assertEquals(getTransformation(), mCipher.getAlgorithm());
+    }
+
+    public void testGetProvider() throws Exception {
+        createCipher();
+        Provider expectedProvider = Security.getProvider("AndroidKeyStoreBCWorkaround");
+        assertSame(expectedProvider, mCipher.getProvider());
+    }
+
+    public void testGetBlockSize() throws Exception {
+        createCipher();
+        assertEquals(getBlockSize(), mCipher.getBlockSize());
+    }
+
+    public void testGetExemptionMechanism() throws Exception {
+        createCipher();
+        assertNull(mCipher.getExemptionMechanism());
+    }
+
+    public void testGetParameters() throws Exception {
+        createCipher();
+        assertAlgoritmParametersIv(null);
+
+        initKat(Cipher.ENCRYPT_MODE);
+        assertAlgoritmParametersIv(getKatIv());
+        doFinal(getKatPlaintext());
+        assertAlgoritmParametersIv(getKatIv());
+
+        initKat(Cipher.DECRYPT_MODE);
+        assertAlgoritmParametersIv(getKatIv());
+        doFinal(getKatCiphertext());
+        assertAlgoritmParametersIv(getKatIv());
+    }
+
+    private void assertAlgoritmParametersIv(byte[] expectedIv)
+            throws InvalidParameterSpecException {
+        AlgorithmParameters actualParameters = mCipher.getParameters();
+        if (expectedIv == null) {
+            assertNull(actualParameters);
+        } else {
+            byte[] actualIv = getIv(actualParameters);
+            assertEquals(expectedIv, actualIv);
+        }
+    }
+
+    public void testGetOutputSizeInEncryptionMode() throws Exception {
+        int blockSize = getBlockSize();
+        createCipher();
+        try {
+            mCipher.getOutputSize(blockSize);
+            fail();
+        } catch (IllegalStateException expected) {}
+
+        initKat(Cipher.ENCRYPT_MODE);
+        if (isAuthenticatedCipher()) {
+            // Authenticated ciphers do not return any output when decrypting until doFinal where
+            // ciphertext is authenticated.
+            for (int input = 0; input <= blockSize * 2; input++) {
+                int actualOutputSize = mCipher.getOutputSize(input);
+                int expectedOutputSize = input + getKatAuthenticationTagLengthBytes();
+                if (actualOutputSize < expectedOutputSize) {
+                    fail("getOutputSize(" + expectedOutputSize + ") underestimated output size"
+                            + ". min expected: <" + expectedOutputSize
+                            + ">, actual: <" + actualOutputSize + ">");
+                }
+            }
+            return;
+        } else if (isStreamCipher()) {
+            // Unauthenticated stream ciphers do not buffer input or output.
+            for (int input = 0; input <= blockSize * 2; input++) {
+                int actualOutputSize = mCipher.getOutputSize(input);
+                if (actualOutputSize < input) {
+                    fail("getOutputSize(" + input + ") underestimated output size. min expected: <"
+                            + input + ">, actual: <" + actualOutputSize + ">");
+                }
+            }
+            return;
+        }
+        // Not a stream cipher -- input may be buffered.
+
+        for (int buffered = 0; buffered < blockSize; buffered++) {
+            // Assert that the output of getOutputSize is not lower than the minimum expected.
+            for (int input = 0; input <= blockSize * 2; input++) {
+                int inputInclBuffered = buffered + input;
+                // doFinal dominates the output size.
+                // One full plaintext block results in one ciphertext block.
+                int minExpectedOutputSize = inputInclBuffered - (inputInclBuffered % blockSize);
+                if (isPaddingEnabled()) {
+                    // Regardless of whether there is a partial input block, an additional block of
+                    // ciphertext should be output.
+                    minExpectedOutputSize += blockSize;
+                } else {
+                    // When no padding is enabled, any remaining partial block of plaintext will
+                    // cause an error. Thus, there's no need to account for its ciphertext.
+                }
+                int actualOutputSize = mCipher.getOutputSize(input);
+                System.out.println("*** buffered: " + buffered + ", input: " + input + ", min: " + minExpectedOutputSize + ", actual: " + actualOutputSize);
+                if (actualOutputSize < minExpectedOutputSize) {
+                    fail("getOutputSize(" + input + ") underestimated output size when buffered == "
+                            + buffered + ". min expected: <"
+                            + minExpectedOutputSize + ">, actual: <" + actualOutputSize + ">");
+                }
+            }
+
+            if (buffered == blockSize - 1) {
+                break;
+            }
+            // Buffer one more byte of input.
+            assertNull("buffered: " + buffered, update(new byte[1]));
+        }
+    }
+
+    public void testGetOutputSizeInDecryptionMode() throws Exception {
+        int blockSize = getBlockSize();
+        createCipher();
+        try {
+            mCipher.getOutputSize(blockSize);
+            fail();
+        } catch (IllegalStateException expected) {}
+
+        initKat(Cipher.DECRYPT_MODE);
+        if ((!isAuthenticatedCipher()) && (isStreamCipher())) {
+            // Unauthenticated stream ciphers do not buffer input or output.
+            for (int input = 0; input <= blockSize * 2; input++) {
+                int actualOutputSize = mCipher.getOutputSize(input);
+                int expectedOutputSize = input;
+                if (actualOutputSize < expectedOutputSize) {
+                    fail("getOutputSize(" + expectedOutputSize + ") underestimated output size"
+                            + ". min expected: <" + expectedOutputSize
+                            + ">, actual: <" + actualOutputSize + ">");
+                }
+            }
+            return;
+        }
+        // Input may be buffered.
+
+        for (int buffered = 0; buffered < blockSize; buffered++) {
+            // Assert that the output of getOutputSize is not lower than the minimum expected.
+            for (int input = 0; input <= blockSize * 2; input++) {
+                int inputInclBuffered = buffered + input;
+                // doFinal dominates the output size.
+                int minExpectedOutputSize;
+                if (isAuthenticatedCipher()) {
+                    // Non-stream authenticated ciphers not supported
+                    assertTrue(isStreamCipher());
+
+                    // Authenticated stream cipher
+                    minExpectedOutputSize =
+                            inputInclBuffered - getKatAuthenticationTagLengthBytes();
+                } else {
+                    // Unauthenticated block cipher.
+
+                    // One full ciphertext block results in one ciphertext block.
+                    minExpectedOutputSize = inputInclBuffered - (inputInclBuffered % blockSize);
+                    if (isPaddingEnabled()) {
+                        if ((inputInclBuffered % blockSize) == 0) {
+                            // No more ciphertext remaining. Thus, the last plaintext block is at
+                            // most blockSize - 1 bytes long.
+                            minExpectedOutputSize--;
+                        } else {
+                            // Partial ciphertext block cannot be decrypted. Thus, the last
+                            // plaintext block would not have been output.
+                            minExpectedOutputSize -= blockSize;
+                        }
+                    } else {
+                        // When no padding is enabled, any remaining ciphertext will cause a error
+                        // because only full blocks can be decrypted. Thus, there's no need to
+                        // account for its plaintext.
+                    }
+                }
+                if (minExpectedOutputSize < 0) {
+                    minExpectedOutputSize = 0;
+                }
+                int actualOutputSize = mCipher.getOutputSize(input);
+                System.out.println("*** buffered: " + buffered + ", input: " + input + ", min: " + minExpectedOutputSize + ", actual: " + actualOutputSize);
+                if (actualOutputSize < minExpectedOutputSize) {
+                    fail("getOutputSize(" + input + ") underestimated output size when buffered == "
+                            + buffered + ". min expected: <"
+                            + minExpectedOutputSize + ">, actual: <" + actualOutputSize + ">");
+                }
+            }
+
+            if (buffered == blockSize - 1) {
+                break;
+            }
+            // Buffer one more byte of input.
+            assertNull("buffered: " + buffered, update(new byte[1]));
+        }
+    }
+
+    public void testInitRequiresIvInDecryptMode() throws Exception {
+        if (getKatIv() == null) {
+            // IV not used in this transformation.
+            return;
+        }
+
+        createCipher();
+        try {
+            init(Cipher.DECRYPT_MODE, getKey());
+            fail();
+        } catch (InvalidKeyException expected) {}
+
+        createCipher();
+        try {
+            init(Cipher.DECRYPT_MODE, getKey(), (SecureRandom) null);
+            fail();
+        } catch (InvalidKeyException expected) {}
+
+        createCipher();
+        try {
+            init(Cipher.DECRYPT_MODE, getKey(), (AlgorithmParameterSpec) null, null);
+            fail();
+        } catch (InvalidAlgorithmParameterException expected) {}
+
+        createCipher();
+        try {
+            init(Cipher.DECRYPT_MODE, getKey(), (AlgorithmParameterSpec) null, null);
+            fail();
+        } catch (InvalidAlgorithmParameterException expected) {}
+
+        createCipher();
+        try {
+            init(Cipher.DECRYPT_MODE, getKey(), (AlgorithmParameters) null, null);
+            fail();
+        } catch (InvalidAlgorithmParameterException expected) {}
+
+        createCipher();
+        try {
+            init(Cipher.DECRYPT_MODE, getKey(), (AlgorithmParameters) null, null);
+            fail();
+        } catch (InvalidAlgorithmParameterException expected) {}
+    }
+
+    public void testGetIV() throws Exception {
+        createCipher();
+        assertNull(mCipher.getIV());
+
+        initKat(Cipher.ENCRYPT_MODE);
+        assertEquals(getKatIv(), mCipher.getIV());
+
+        byte[] ciphertext = doFinal(new byte[getBlockSize()]);
+        assertEquals(getKatIv(), mCipher.getIV());
+
+        createCipher();
+        initKat(Cipher.DECRYPT_MODE);
+        assertEquals(getKatIv(), mCipher.getIV());
+
+        doFinal(ciphertext);
+        assertEquals(getKatIv(), mCipher.getIV());
+    }
+
+    public void testIvGeneratedAndUsedWhenEncryptingWithoutExplicitIv() throws Exception {
+        createCipher();
+        SecretKey key = getKey();
+        init(Cipher.ENCRYPT_MODE, key);
+        byte[] generatedIv = mCipher.getIV();
+        AlgorithmParameters generatedParams = mCipher.getParameters();
+        if (getKatIv() == null) {
+            // IV not needed by this transformation -- shouldn't have been generated by Cipher.init
+            assertNull(generatedIv);
+            assertNull(generatedParams);
+        } else {
+            // IV is needed by this transformation -- should've been generated by Cipher.init
+            assertNotNull(generatedIv);
+            assertEquals(getKatIv().length, generatedIv.length);
+            assertNotNull(generatedParams);
+            assertEquals(generatedIv, getIv(generatedParams));
+        }
+
+        // Assert that encrypting then decrypting using the above IV (or null) results in the
+        // original plaintext.
+        byte[] plaintext = new byte[getBlockSize()];
+        byte[] ciphertext = doFinal(plaintext);
+        createCipher();
+        init(Cipher.DECRYPT_MODE, key, generatedParams);
+        byte[] decryptedPlaintext = mCipher.doFinal(ciphertext);
+        assertEquals(plaintext, decryptedPlaintext);
+    }
+
+    public void testGeneratedIvSurvivesReset() throws Exception {
+        if (getKatIv() == null) {
+            // This transformation does not use an IV
+            return;
+        }
+
+        createCipher();
+        init(Cipher.ENCRYPT_MODE, getKey());
+        byte[] iv = mCipher.getIV();
+        AlgorithmParameters generatedParams = mCipher.getParameters();
+        byte[] ciphertext = mCipher.doFinal(getKatPlaintext());
+        // Assert that the IV is still there
+        assertEquals(iv, mCipher.getIV());
+        assertAlgoritmParametersIv(iv);
+
+        if (getKatIv() != null) {
+            // We try to prevent IV reuse by not letting the Cipher be reused.
+            return;
+        }
+
+        // Assert that encrypting the same input after the above reset produces the same ciphertext.
+        assertEquals(ciphertext, mCipher.doFinal(getKatPlaintext()));
+
+        assertEquals(iv, mCipher.getIV());
+        assertAlgoritmParametersIv(iv);
+
+        // Just in case, test with a new instance of Cipher with the same parameters
+        createCipher();
+        init(Cipher.ENCRYPT_MODE, getKey(), generatedParams);
+        assertEquals(ciphertext, mCipher.doFinal(getKatPlaintext()));
+    }
+
+    public void testGeneratedIvDoesNotSurviveReinitialization() throws Exception {
+        if (getKatIv() == null) {
+            // This transformation does not use an IV
+            return;
+        }
+
+        createCipher();
+        init(Cipher.ENCRYPT_MODE, getKey());
+        byte[] ivBeforeReinitialization = mCipher.getIV();
+
+        init(Cipher.ENCRYPT_MODE, getKey());
+        // A new IV should've been generated
+        if (Arrays.equals(ivBeforeReinitialization, mCipher.getIV())) {
+            fail("Same auto-generated IV after Cipher reinitialized."
+                    + " Broken implementation or you're very unlucky (p: 2^{-"
+                    + (ivBeforeReinitialization.length * 8) + "})");
+        }
+    }
+
+    public void testExplicitlySetIvDoesNotSurviveReinitialization() throws Exception {
+        if (getKatIv() == null) {
+            // This transformation does not use an IV
+            return;
+        }
+
+        createCipher();
+        initKat(Cipher.ENCRYPT_MODE);
+        init(Cipher.ENCRYPT_MODE, getKey());
+        // A new IV should've been generated
+        if (Arrays.equals(getKatIv(), mCipher.getIV())) {
+            fail("Auto-generated IV after Cipher reinitialized is the same as previous IV."
+                    + " Broken implementation or you're very unlucky (p: 2^{-"
+                    + (getKatIv().length * 8) + "})");
+        }
+    }
+
+    public void testReinitializingInDecryptModeDoesNotUsePreviouslyUsedIv() throws Exception {
+        if (getKatIv() == null) {
+            // This transformation does not use an IV
+            return;
+        }
+
+        createCipher();
+        // Initialize with explicitly provided IV
+        init(Cipher.ENCRYPT_MODE, getKey(), getKatAlgorithmParameterSpec());
+        // Make sure the IV has been used, just in case it's set/cached lazily.
+        mCipher.update(new byte[getBlockSize() * 2]);
+
+        // IV required but not provided
+        try {
+            init(Cipher.DECRYPT_MODE, getKey());
+            fail();
+        } catch (InvalidKeyException expected) {}
+
+        createCipher();
+        // Initialize with a generated IV
+        init(Cipher.ENCRYPT_MODE, getKey());
+        mCipher.doFinal(getKatPlaintext());
+
+        // IV required but not provided
+        try {
+            init(Cipher.DECRYPT_MODE, getKey());
+            fail();
+        } catch (InvalidKeyException expected) {}
+
+        // IV required but not provided
+        try {
+            init(Cipher.DECRYPT_MODE, getKey(), (SecureRandom) null);
+            fail();
+        } catch (InvalidKeyException expected) {}
+
+        // IV required but not provided
+        try {
+            init(Cipher.DECRYPT_MODE, getKey(), (AlgorithmParameterSpec) null);
+            fail();
+        } catch (InvalidAlgorithmParameterException expected) {}
+
+        // IV required but not provided
+        try {
+            init(Cipher.DECRYPT_MODE, getKey(), (AlgorithmParameterSpec) null, null);
+            fail();
+        } catch (InvalidAlgorithmParameterException expected) {}
+
+        // IV required but not provided
+        try {
+            init(Cipher.DECRYPT_MODE, getKey(), (AlgorithmParameters) null);
+            fail();
+        } catch (InvalidAlgorithmParameterException expected) {}
+
+        // IV required but not provided
+        try {
+            init(Cipher.DECRYPT_MODE, getKey(), (AlgorithmParameters) null, null);
+            fail();
+        } catch (InvalidAlgorithmParameterException expected) {}
+    }
+
+    public void testKeyDoesNotSurviveReinitialization() throws Exception {
+        assertKeyDoesNotSurviveReinitialization(Cipher.ENCRYPT_MODE);
+        assertKeyDoesNotSurviveReinitialization(Cipher.DECRYPT_MODE);
+    }
+
+    private void assertKeyDoesNotSurviveReinitialization(int opmode) throws Exception {
+        byte[] input = getKatInput(opmode);
+        createCipher();
+        byte[] katKeyBytes = getKatKey();
+        SecretKey key1 = importKey(katKeyBytes);
+        init(opmode, key1, getKatAlgorithmParameterSpec());
+        byte[] output1 = doFinal(input);
+
+        // Create a different key by flipping a bit in the KAT key.
+        katKeyBytes[0] ^= 1;
+        SecretKey key2 = importKey(katKeyBytes);
+
+        init(opmode, key2, getKatAlgorithmParameterSpec());
+        byte[] output2;
+        try {
+            output2 = doFinal(input);
+        } catch (BadPaddingException expected) {
+            // Padding doesn't decode probably because the new key is being used. This can only
+            // occur is padding is used.
+            return;
+        }
+
+        // Either padding wasn't used or the old key was used.
+        if (Arrays.equals(output1, output2)) {
+            fail("Same output when reinitialized with a different key. opmode: " + opmode);
+        }
+    }
+
+    public void testDoFinalResets() throws Exception {
+        assertDoFinalResetsCipher(Cipher.DECRYPT_MODE);
+        assertDoFinalResetsCipher(Cipher.ENCRYPT_MODE);
+    }
+
+    private void assertDoFinalResetsCipher(int opmode) throws Exception {
+        byte[] input = getKatInput(opmode);
+        byte[] expectedOutput = getKatOutput(opmode);
+
+        createCipher();
+        initKat(opmode);
+        assertEquals(expectedOutput, doFinal(input));
+
+        if ((opmode == Cipher.ENCRYPT_MODE) && (getKatIv() != null)) {
+            // Assert that this cipher cannot be reused (thus making IV reuse harder)
+            try {
+                doFinal(input);
+                fail();
+            } catch (IllegalStateException expected) {}
+            return;
+        }
+
+        // Assert that the same output is produced after the above reset
+        assertEquals(expectedOutput, doFinal(input));
+
+        // Assert that the same output is produced after the above reset. This time, make update()
+        // buffer half a block of input.
+        if (input.length < getBlockSize() * 2) {
+            fail("This test requires an input which is at least two blocks long");
+        }
+        assertEquals(expectedOutput, concat(
+                update(subarray(input, 0, getBlockSize() * 3 / 2)),
+                doFinal(subarray(input, getBlockSize() * 3 / 2, input.length))));
+
+        // Assert that the same output is produced after the above reset, despite half of the block
+        // having been buffered prior to the reset. This is in case the implementation does not
+        // empty that buffer when resetting.
+        assertEquals(expectedOutput, doFinal(input));
+
+        // Assert that the IV with which the cipher was initialized is still there after the resets.
+        assertEquals(getKatIv(), mCipher.getIV());
+        assertAlgoritmParametersIv(getKatIv());
+    }
+
+    public void testUpdateWithEmptyInputReturnsCorrectValue() throws Exception {
+        // Test encryption
+        createCipher();
+        initKat(Cipher.ENCRYPT_MODE);
+        assertUpdateWithEmptyInputReturnsNull();
+
+        // Test decryption
+        createCipher();
+        initKat(Cipher.DECRYPT_MODE);
+        assertUpdateWithEmptyInputReturnsNull();
+    }
+
+    private void assertUpdateWithEmptyInputReturnsNull() {
+        assertEquals(null, update(new byte[0]));
+        assertEquals(null, update(new byte[getBlockSize() * 2], getBlockSize(), 0));
+        assertEquals(null, update(new byte[getBlockSize()], 0, 0));
+
+        // Feed two blocks through the Cipher, so that it's in a state where a block of input
+        // produces a block of output.
+        // Two blocks are used instead of one because when decrypting with padding enabled, output
+        // lags behind input by a block because the Cipher doesn't know whether the most recent
+        // input block was supposed to contain padding.
+        update(new byte[getBlockSize() * 2]);
+
+        assertEquals(null, update(new byte[0]));
+        assertEquals(null, update(new byte[getBlockSize() * 2], getBlockSize(), 0));
+        assertEquals(null, update(new byte[getBlockSize()], 0, 0));
+    }
+
+    public void testUpdateDoesNotProduceOutputWhenInsufficientInput() throws Exception {
+        if (isStreamCipher()) {
+            // Stream ciphers always produce output for non-empty input.
+            return;
+        }
+
+        // Test encryption
+        createCipher();
+        initKat(Cipher.ENCRYPT_MODE);
+        assertUpdateDoesNotProduceOutputWhenInsufficientInput();
+
+        // Test decryption
+        createCipher();
+        initKat(Cipher.DECRYPT_MODE);
+        assertUpdateDoesNotProduceOutputWhenInsufficientInput();
+    }
+
+    private void assertUpdateDoesNotProduceOutputWhenInsufficientInput() throws Exception {
+        if (getBlockSize() < 8) {
+            fail("This test isn't designed for small block size: " + getBlockSize());
+        }
+
+        assertEquals(null, update(new byte[1]));
+        assertEquals(null, update(new byte[1], 0, 1));
+        assertEquals(0, update(new byte[1], 0, 1, new byte[getBlockSize()]));
+        assertEquals(0, update(new byte[1], 0, 1, new byte[getBlockSize()], 0));
+        assertEquals(0, update(ByteBuffer.allocate(1), ByteBuffer.allocate(getBlockSize())));
+
+        // Feed a block through the Cipher, so that it's potentially no longer in an initial state.
+        byte[] output = update(new byte[getBlockSize()]);
+        assertEquals(getBlockSize(), output.length);
+
+        assertEquals(null, update(new byte[1]));
+        assertEquals(null, update(new byte[1], 0, 1));
+        assertEquals(0, update(new byte[1], 0, 1, new byte[getBlockSize()]));
+        assertEquals(0, update(new byte[1], 0, 1, new byte[getBlockSize()], 0));
+        assertEquals(0, update(ByteBuffer.allocate(1), ByteBuffer.allocate(getBlockSize())));
+    }
+
+    public void testKatOneShotEncryptUsingDoFinal() throws Exception {
+        createCipher();
+        assertKatOneShotTransformUsingDoFinal(
+                Cipher.ENCRYPT_MODE, getKatPlaintext(), getKatCiphertext());
+    }
+
+    public void testKatOneShotDecryptUsingDoFinal() throws Exception {
+        createCipher();
+        assertKatOneShotTransformUsingDoFinal(
+                Cipher.DECRYPT_MODE, getKatCiphertext(), getKatPlaintext());
+    }
+
+    private void assertKatOneShotTransformUsingDoFinal(
+            int opmode, byte[] input, byte[] expectedOutput) throws Exception {
+        int bufferWithInputInTheMiddleCleartextOffset = 5;
+        byte[] bufferWithInputInTheMiddle = concat(
+                new byte[bufferWithInputInTheMiddleCleartextOffset],
+                input,
+                new byte[4]);
+
+        initKat(opmode);
+        assertEquals(expectedOutput, doFinal(input));
+        initKat(opmode);
+        assertEquals(expectedOutput, doFinal(input, 0, input.length));
+        initKat(opmode);
+        assertEquals(expectedOutput,
+                doFinal(bufferWithInputInTheMiddle,
+                        bufferWithInputInTheMiddleCleartextOffset,
+                        input.length));
+
+        ByteBuffer inputBuffer = ByteBuffer.wrap(
+                bufferWithInputInTheMiddle,
+                bufferWithInputInTheMiddleCleartextOffset,
+                input.length);
+        ByteBuffer actualOutputBuffer = ByteBuffer.allocate(expectedOutput.length);
+        initKat(opmode);
+        assertEquals(expectedOutput.length, doFinal(inputBuffer, actualOutputBuffer));
+        assertEquals(0, inputBuffer.remaining());
+        assertByteBufferEquals(
+                (ByteBuffer) ByteBuffer.wrap(expectedOutput).position(expectedOutput.length),
+                actualOutputBuffer);
+    }
+
+    public void testKatEncryptOneByteAtATime() throws Exception {
+        createCipher();
+        initKat(Cipher.ENCRYPT_MODE);
+        byte[] plaintext = getKatPlaintext();
+        byte[] expectedCiphertext = getKatCiphertext();
+        int blockSize = getBlockSize();
+        if (isStreamCipher()) {
+            // Stream cipher -- one byte in, one byte out
+            for (int plaintextIndex = 0; plaintextIndex < plaintext.length; plaintextIndex++) {
+                byte[] output = update(new byte[] {plaintext[plaintextIndex]});
+                assertEquals("plaintext index: " + plaintextIndex, 1, output.length);
+                assertEquals("plaintext index: " + plaintextIndex,
+                        expectedCiphertext[plaintextIndex], output[0]);
+            }
+            byte[] finalOutput = doFinal();
+            byte[] expectedFinalOutput;
+            if (isAuthenticatedCipher()) {
+                expectedFinalOutput =
+                        subarray(expectedCiphertext, plaintext.length, expectedCiphertext.length);
+            } else {
+                expectedFinalOutput = EmptyArray.BYTE;
+            }
+            assertEquals(expectedFinalOutput, finalOutput);
+        } else {
+            // Not a stream cipher -- operates on full blocks only.
+
+            // Assert that a block of output is produced once a full block of input is provided.
+            // Every input block produces an output block.
+            int ciphertextIndex = 0;
+            for (int plaintextIndex = 0; plaintextIndex < plaintext.length; plaintextIndex++) {
+                byte[] output = update(new byte[] {plaintext[plaintextIndex]});
+                if ((plaintextIndex % blockSize) == blockSize - 1) {
+                    // Cipher.update is expected to have output a new block
+                    assertEquals(
+                            "plaintext index: " + plaintextIndex,
+                            subarray(
+                                    expectedCiphertext,
+                                    ciphertextIndex,
+                                    ciphertextIndex + blockSize),
+                            output);
+                } else {
+                    // Cipher.update is expected to have produced no output
+                    assertEquals("plaintext index: " + plaintextIndex, null, output);
+                }
+                if (output != null) {
+                    ciphertextIndex += output.length;
+                }
+            }
+
+            byte[] actualFinalOutput = doFinal();
+            byte[] expectedFinalOutput =
+                    subarray(expectedCiphertext, ciphertextIndex, expectedCiphertext.length);
+            assertEquals(expectedFinalOutput, actualFinalOutput);
+        }
+    }
+
+    public void testKatDecryptOneByteAtATime() throws Exception {
+        createCipher();
+        initKat(Cipher.DECRYPT_MODE);
+        byte[] ciphertext = getKatCiphertext();
+        int plaintextIndex = 0;
+        int blockSize = getBlockSize();
+        byte[] expectedPlaintext = getKatPlaintext();
+        boolean paddingEnabled = isPaddingEnabled();
+        if (isAuthenticatedCipher()) {
+            // Authenticated cipher -- no output until doFinal where ciphertext is authenticated.
+            for (int ciphertextIndex = 0; ciphertextIndex < ciphertext.length; ciphertextIndex++) {
+                byte[] output = update(new byte[] {ciphertext[ciphertextIndex]});
+                assertEquals("ciphertext index: " + ciphertextIndex,
+                        0, (output != null) ? output.length : 0);
+            }
+            byte[] finalOutput = doFinal();
+            assertEquals(expectedPlaintext, finalOutput);
+        } else if (isStreamCipher()) {
+            // Unauthenticated stream cipher -- one byte in, one byte out
+            for (int ciphertextIndex = 0; ciphertextIndex < ciphertext.length; ciphertextIndex++) {
+                byte[] output = update(new byte[] {ciphertext[ciphertextIndex]});
+                assertEquals("ciphertext index: " + ciphertextIndex, 1, output.length);
+                assertEquals("ciphertext index: " + ciphertextIndex,
+                        expectedPlaintext[ciphertextIndex], output[0]);
+            }
+            byte[] finalOutput = doFinal();
+            assertEquals(0, finalOutput.length);
+        } else {
+            // Unauthenticated block cipher -- operates in full blocks only
+
+            // Assert that a block of output is produced once a full block of input is provided.
+            // When padding is used, output is produced one input byte later: once the first byte of the
+            // next input block is provided.
+            for (int ciphertextIndex = 0; ciphertextIndex < ciphertext.length; ciphertextIndex++) {
+                byte[] output = update(new byte[] {ciphertext[ciphertextIndex]});
+                boolean outputExpected =
+                        ((paddingEnabled)
+                                && (ciphertextIndex > 0) && ((ciphertextIndex % blockSize) == 0))
+                        || ((!paddingEnabled) && ((ciphertextIndex % blockSize) == blockSize - 1));
+
+                if (outputExpected) {
+                    assertEquals(
+                            "ciphertext index: " + ciphertextIndex,
+                            subarray(expectedPlaintext, plaintextIndex, plaintextIndex + blockSize),
+                            output);
+                } else {
+                    assertEquals("ciphertext index: " + ciphertextIndex, null, output);
+                }
+
+                if (output != null) {
+                    plaintextIndex += output.length;
+                }
+            }
+
+            byte[] actualFinalOutput = doFinal();
+            byte[] expectedFinalOutput =
+                    subarray(expectedPlaintext, plaintextIndex, expectedPlaintext.length);
+            assertEquals(expectedFinalOutput, actualFinalOutput);
+        }
+    }
+
+    public void testUpdateAADNotSupported() throws Exception {
+        createCipher();
+        initKat(Cipher.ENCRYPT_MODE);
+        if (isAuthenticatedCipher()) {
+            assertUpdateAADSupported();
+        } else {
+            assertUpdateAADNotSupported();
+        }
+
+        createCipher();
+        initKat(Cipher.DECRYPT_MODE);
+        if (isAuthenticatedCipher()) {
+            assertUpdateAADSupported();
+        } else {
+            assertUpdateAADNotSupported();
+        }
+    }
+
+    private void assertUpdateAADNotSupported() throws Exception {
+        try {
+            mCipher.updateAAD(new byte[getBlockSize()]);
+            fail();
+        } catch (UnsupportedOperationException expected) {
+        } catch (IllegalStateException expected) {}
+
+        try {
+            mCipher.updateAAD(new byte[getBlockSize()], 0, getBlockSize());
+            fail();
+        } catch (UnsupportedOperationException expected) {
+        } catch (IllegalStateException expected) {}
+
+        try {
+            mCipher.updateAAD(ByteBuffer.allocate(getBlockSize()));
+            fail();
+        } catch (UnsupportedOperationException expected) {
+        } catch (IllegalStateException expected) {}
+    }
+
+    private void assertUpdateAADSupported() throws Exception {
+        mCipher.updateAAD(new byte[getBlockSize()]);
+        mCipher.updateAAD(new byte[getBlockSize()], 0, getBlockSize());
+        mCipher.updateAAD(ByteBuffer.allocate(getBlockSize()));
+    }
+
+    // TODO: Add tests for WRAP and UNWRAP
+
+    public void testUpdateAndDoFinalNotSupportedInWrapAndUnwrapModes() throws Exception {
+        createCipher();
+        assertUpdateAndDoFinalThrowIllegalStateExceprtion(
+                Cipher.WRAP_MODE, getKey(), getKatAlgorithmParameterSpec());
+
+        createCipher();
+        assertUpdateAndDoFinalThrowIllegalStateExceprtion(
+                Cipher.UNWRAP_MODE, getKey(), getKatAlgorithmParameterSpec());
+    }
+
+    private void assertUpdateAndDoFinalThrowIllegalStateExceprtion(
+            int opmode, SecretKey key, AlgorithmParameterSpec paramSpec)
+            throws Exception {
+        try {
+            init(opmode, key, paramSpec);
+        } catch (UnsupportedOperationException e) {
+            // Skip this test because wrap/unwrap is not supported by this Cipher
+            return;
+        }
+
+        try {
+            update(new byte[getBlockSize()]);
+            fail();
+        } catch (IllegalStateException expected) {}
+
+        init(opmode, key, paramSpec);
+        try {
+            update(new byte[getBlockSize()], 0, getBlockSize());
+            fail();
+        } catch (IllegalStateException expected) {}
+
+        init(opmode, key, paramSpec);
+        try {
+            update(new byte[getBlockSize()], 0, getBlockSize(), new byte[getBlockSize() * 2]);
+            fail();
+        } catch (IllegalStateException expected) {}
+
+        init(opmode, key, paramSpec);
+        try {
+            update(new byte[getBlockSize()], 0, getBlockSize(), new byte[getBlockSize() * 2], 0);
+            fail();
+        } catch (IllegalStateException expected) {}
+
+        init(opmode, key, paramSpec);
+        try {
+            update(ByteBuffer.allocate(getBlockSize()), ByteBuffer.allocate(getBlockSize() * 2));
+            fail();
+        } catch (IllegalStateException expected) {}
+
+        init(opmode, key, paramSpec);
+        try {
+            doFinal();
+            fail();
+        } catch (IllegalStateException expected) {}
+
+        init(opmode, key, paramSpec);
+        try {
+            doFinal(new byte[getBlockSize()]);
+            fail();
+        } catch (IllegalStateException expected) {}
+
+        init(opmode, key, paramSpec);
+        try {
+            doFinal(new byte[getBlockSize()], 0, getBlockSize());
+            fail();
+        } catch (IllegalStateException expected) {}
+
+        init(opmode, key, paramSpec);
+        try {
+            doFinal(new byte[getBlockSize() * 2], 0);
+            fail();
+        } catch (IllegalStateException expected) {}
+
+        init(opmode, key, paramSpec);
+        try {
+            doFinal(new byte[getBlockSize()], 0, getBlockSize(), new byte[getBlockSize() * 2]);
+            fail();
+        } catch (IllegalStateException expected) {}
+
+        init(opmode, key, paramSpec);
+        try {
+            doFinal(new byte[getBlockSize()], 0, getBlockSize(), new byte[getBlockSize() * 2], 0);
+            fail();
+        } catch (IllegalStateException expected) {}
+
+        init(opmode, key, paramSpec);
+        try {
+            doFinal(ByteBuffer.allocate(getBlockSize()), ByteBuffer.allocate(getBlockSize() * 2));
+            fail();
+        } catch (IllegalStateException expected) {}
+    }
+
+    public void testGeneratedPadding() throws Exception {
+        // Assert that the Cipher under test correctly handles plaintexts of various lengths.
+        if (isStreamCipher()) {
+            // Not applicable to stream ciphers
+            return;
+        }
+
+        // Encryption of basePlaintext and additional data should result in baseCiphertext and some
+        // data (some of which may be padding).
+        int blockSize = getBlockSize();
+        byte[] basePlaintext = subarray(getKatPlaintext(), 0, blockSize);
+        byte[] baseCiphertext = subarray(getKatCiphertext(), 0, blockSize);
+        boolean paddingEnabled = isPaddingEnabled();
+
+        for (int lastInputBlockUnusedByteCount = 0;
+                lastInputBlockUnusedByteCount < blockSize;
+                lastInputBlockUnusedByteCount++) {
+            byte[] plaintext = concat(basePlaintext, new byte[lastInputBlockUnusedByteCount]);
+            createCipher();
+            initKat(Cipher.ENCRYPT_MODE);
+
+            if ((!paddingEnabled) && ((lastInputBlockUnusedByteCount % blockSize) != 0)) {
+                // Without padding, plaintext which does not end with a full block should be
+                // rejected.
+                try {
+                    doFinal(plaintext);
+                    fail();
+                } catch (IllegalBlockSizeException expected) {}
+                continue;
+            }
+            byte[] ciphertext = doFinal(plaintext);
+
+            assertEquals(
+                    "lastInputBlockUnusedByteCount: " + lastInputBlockUnusedByteCount,
+                    baseCiphertext,
+                    subarray(ciphertext, 0, baseCiphertext.length));
+
+            int expectedCiphertextLength = getExpectedCiphertextLength(plaintext.length);
+            int expectedDecryptedPlaintextLength =
+                    (paddingEnabled) ? plaintext.length : expectedCiphertextLength;
+            assertEquals(
+                    "lastInputBlockUnusedByteCount: " + lastInputBlockUnusedByteCount,
+                    expectedCiphertextLength,
+                    ciphertext.length);
+            initKat(Cipher.DECRYPT_MODE);
+            byte[] decryptedPlaintext = doFinal(ciphertext);
+            assertEquals(
+                    "lastInputBlockUnusedByteCount: " + lastInputBlockUnusedByteCount,
+                    expectedDecryptedPlaintextLength,
+                    decryptedPlaintext.length);
+            assertEquals(
+                    "lastInputBlockUnusedByteCount: " + lastInputBlockUnusedByteCount,
+                    basePlaintext,
+                    subarray(decryptedPlaintext, 0, basePlaintext.length));
+        }
+    }
+
+    public void testDecryptWithMangledPadding() throws Exception {
+        if (!isPaddingEnabled()) {
+            // Test not applicable when padding not in use
+            return;
+        }
+
+        createCipher();
+        initKat(Cipher.DECRYPT_MODE);
+        byte[] ciphertext = getKatCiphertext();
+        // Flip a bit in the last byte of ciphertext -- this should result in the last plaintext
+        // block getting mangled. In turn, this should result in bad padding.
+        ciphertext[ciphertext.length - 1] ^= 1;
+        try {
+            doFinal(ciphertext);
+            fail();
+        } catch (BadPaddingException expected) {}
+    }
+
+    public void testDecryptWithMissingPadding() throws Exception {
+        if (!isPaddingEnabled()) {
+            // Test not applicable when padding not in use
+            return;
+        }
+
+        createCipher();
+        initKat(Cipher.DECRYPT_MODE);
+        byte[] ciphertext = subarray(getKatCiphertext(), 0, getBlockSize());
+        try {
+            doFinal(ciphertext);
+            fail();
+        } catch (BadPaddingException expected) {}
+    }
+
+    public void testUpdateCopySafe() throws Exception {
+        // Assert that when input and output buffers passed to Cipher.update reference the same
+        // byte array, then no input data is overwritten before it's consumed.
+        assertUpdateCopySafe(Cipher.ENCRYPT_MODE, 0, 0);
+        assertUpdateCopySafe(Cipher.ENCRYPT_MODE, 0, 1);
+        assertUpdateCopySafe(Cipher.ENCRYPT_MODE, 1, 0);
+        assertUpdateCopySafe(Cipher.ENCRYPT_MODE, 0, getBlockSize() - 1);
+        assertUpdateCopySafe(Cipher.ENCRYPT_MODE, 0, getBlockSize());
+        assertUpdateCopySafe(Cipher.ENCRYPT_MODE, 0, getBlockSize() + 1);
+        assertUpdateCopySafe(Cipher.ENCRYPT_MODE, getBlockSize() * 2 - 1, 0);
+        assertUpdateCopySafe(Cipher.ENCRYPT_MODE, getBlockSize() * 2, 0);
+        assertUpdateCopySafe(Cipher.ENCRYPT_MODE, getBlockSize() * 2 + 1, 0);
+
+        assertUpdateCopySafe(Cipher.DECRYPT_MODE, 0, 0);
+        assertUpdateCopySafe(Cipher.DECRYPT_MODE, 0, 1);
+        assertUpdateCopySafe(Cipher.DECRYPT_MODE, 1, 0);
+        assertUpdateCopySafe(Cipher.DECRYPT_MODE, 0, getBlockSize() - 1);
+        assertUpdateCopySafe(Cipher.DECRYPT_MODE, 0, getBlockSize());
+        assertUpdateCopySafe(Cipher.DECRYPT_MODE, 0, getBlockSize() + 1);
+        assertUpdateCopySafe(Cipher.DECRYPT_MODE, getBlockSize() * 2 - 1, 0);
+        assertUpdateCopySafe(Cipher.DECRYPT_MODE, getBlockSize() * 2, 0);
+        assertUpdateCopySafe(Cipher.DECRYPT_MODE, getBlockSize() * 2 + 1, 0);
+    }
+
+    private void assertUpdateCopySafe(
+            int opmode, int inputOffsetInBuffer, int outputOffsetInBuffer)
+            throws Exception {
+        int blockSize = getBlockSize();
+        byte[] input;
+        byte[] expectedOutput;
+        switch (opmode) {
+            case Cipher.ENCRYPT_MODE:
+                input = getKatPlaintext();
+                if (isStreamCipher()) {
+                    if (isAuthenticatedCipher()) {
+                        expectedOutput = subarray(getKatCiphertext(), 0, input.length);
+                    } else {
+                        expectedOutput = getKatCiphertext();
+                    }
+                } else {
+                    // Update outputs exactly one block of ciphertext for one block of plaintext,
+                    // excluding padding.
+                    expectedOutput = subarray(
+                            getKatCiphertext(), 0, (input.length / blockSize) * blockSize);
+                }
+                break;
+            case Cipher.DECRYPT_MODE:
+                input = getKatCiphertext();
+                if (isAuthenticatedCipher()) {
+                    expectedOutput = EmptyArray.BYTE;
+                } else if (isStreamCipher()) {
+                    expectedOutput = getKatPlaintext();
+                } else {
+                    expectedOutput = getKatPlaintext();
+                    if (isPaddingEnabled()) {
+                        // When padding is enabled, update will not output the last block of
+                        // plaintext because it doesn't know whether more ciphertext will be
+                        // provided.
+                        expectedOutput = subarray(
+                                expectedOutput, 0, ((input.length / blockSize) - 1) * blockSize);
+                    } else {
+                        // When no padding is used, one block of ciphertext results in one block of
+                        // plaintext.
+                        expectedOutput = subarray(
+                                expectedOutput, 0, (input.length - (input.length % blockSize)));
+                    }
+                }
+                break;
+            default:
+                throw new AssertionFailedError("Unsupported opmode: " + opmode);
+        }
+
+        int inputEndIndexInBuffer = inputOffsetInBuffer + input.length;
+        int outputEndIndexInBuffer = outputOffsetInBuffer + expectedOutput.length;
+
+        // Test the update(byte[], int, int, byte[], int) variant
+        byte[] buffer = new byte[Math.max(inputEndIndexInBuffer, outputEndIndexInBuffer)];
+        System.arraycopy(input, 0, buffer, inputOffsetInBuffer, input.length);
+        createCipher();
+        initKat(opmode);
+        assertEquals(expectedOutput.length,
+                update(buffer, inputOffsetInBuffer, input.length,
+                        buffer, outputOffsetInBuffer));
+        assertEquals(expectedOutput,
+                subarray(buffer, outputOffsetInBuffer, outputEndIndexInBuffer));
+
+        if (outputOffsetInBuffer == 0) {
+            // We can use the update variant which assumes that output offset is 0.
+            buffer = new byte[Math.max(inputEndIndexInBuffer, outputEndIndexInBuffer)];
+            System.arraycopy(input, 0, buffer, inputOffsetInBuffer, input.length);
+            createCipher();
+            initKat(opmode);
+            assertEquals(expectedOutput.length,
+                    update(buffer, inputOffsetInBuffer, input.length, buffer));
+            assertEquals(expectedOutput,
+                    subarray(buffer, outputOffsetInBuffer, outputEndIndexInBuffer));
+        }
+
+        // Test the update(ByteBuffer, ByteBuffer) variant
+        buffer = new byte[Math.max(inputEndIndexInBuffer, outputEndIndexInBuffer)];
+        System.arraycopy(input, 0, buffer, inputOffsetInBuffer, input.length);
+        ByteBuffer inputBuffer = ByteBuffer.wrap(buffer, inputOffsetInBuffer, input.length);
+        ByteBuffer outputBuffer =
+                ByteBuffer.wrap(buffer, outputOffsetInBuffer, expectedOutput.length);
+        createCipher();
+        initKat(opmode);
+        assertEquals(expectedOutput.length, update(inputBuffer, outputBuffer));
+        assertEquals(expectedOutput,
+                subarray(buffer, outputOffsetInBuffer, outputEndIndexInBuffer));
+    }
+
+    public void testDoFinalCopySafe() throws Exception {
+        // Assert that when input and output buffers passed to Cipher.doFinal reference the same
+        // byte array, then no input data is overwritten before it's consumed.
+        assertDoFinalCopySafe(Cipher.ENCRYPT_MODE, 0, 0);
+        assertDoFinalCopySafe(Cipher.ENCRYPT_MODE, 0, 1);
+        assertDoFinalCopySafe(Cipher.ENCRYPT_MODE, 1, 0);
+        assertDoFinalCopySafe(Cipher.ENCRYPT_MODE, 0, getBlockSize() - 1);
+        assertDoFinalCopySafe(Cipher.ENCRYPT_MODE, 0, getBlockSize());
+        assertDoFinalCopySafe(Cipher.ENCRYPT_MODE, 0, getBlockSize() + 1);
+        assertDoFinalCopySafe(Cipher.ENCRYPT_MODE, getBlockSize() * 2 - 1, 0);
+        assertDoFinalCopySafe(Cipher.ENCRYPT_MODE, getBlockSize() * 2, 0);
+        assertDoFinalCopySafe(Cipher.ENCRYPT_MODE, getBlockSize() * 2 + 1, 0);
+
+        assertDoFinalCopySafe(Cipher.DECRYPT_MODE, 0, 0);
+        assertDoFinalCopySafe(Cipher.DECRYPT_MODE, 0, 1);
+        assertDoFinalCopySafe(Cipher.DECRYPT_MODE, 1, 0);
+        assertDoFinalCopySafe(Cipher.DECRYPT_MODE, 0, getBlockSize() - 1);
+        assertDoFinalCopySafe(Cipher.DECRYPT_MODE, 0, getBlockSize());
+        assertDoFinalCopySafe(Cipher.DECRYPT_MODE, 0, getBlockSize() + 1);
+        assertDoFinalCopySafe(Cipher.DECRYPT_MODE, getBlockSize() * 2 - 1, 0);
+        assertDoFinalCopySafe(Cipher.DECRYPT_MODE, getBlockSize() * 2, 0);
+        assertDoFinalCopySafe(Cipher.DECRYPT_MODE, getBlockSize() * 2 + 1, 0);
+    }
+
+    private void assertDoFinalCopySafe(
+            int opmode, int inputOffsetInBuffer, int outputOffsetInBuffer)
+            throws Exception {
+        byte[] input = getKatInput(opmode);
+        byte[] expectedOutput = getKatOutput(opmode);
+
+        int inputEndIndexInBuffer = inputOffsetInBuffer + input.length;
+        int outputEndIndexInBuffer = outputOffsetInBuffer + expectedOutput.length;
+
+        // Test the doFinal(byte[], int, int, byte[], int) variant
+        byte[] buffer = new byte[Math.max(inputEndIndexInBuffer, outputEndIndexInBuffer)];
+        System.arraycopy(input, 0, buffer, inputOffsetInBuffer, input.length);
+        createCipher();
+        initKat(opmode);
+        assertEquals(expectedOutput.length,
+                doFinal(buffer, inputOffsetInBuffer, input.length,
+                        buffer, outputOffsetInBuffer));
+        assertEquals(expectedOutput,
+                subarray(buffer, outputOffsetInBuffer, outputEndIndexInBuffer));
+
+        if (outputOffsetInBuffer == 0) {
+            // We can use the doFinal variant which assumes that output offset is 0.
+            buffer = new byte[Math.max(inputEndIndexInBuffer, outputEndIndexInBuffer)];
+            System.arraycopy(input, 0, buffer, inputOffsetInBuffer, input.length);
+            createCipher();
+            initKat(opmode);
+            assertEquals(expectedOutput.length,
+                    doFinal(buffer, inputOffsetInBuffer, input.length, buffer));
+            assertEquals(expectedOutput,
+                    subarray(buffer, outputOffsetInBuffer, outputEndIndexInBuffer));
+        }
+
+        // Test the doFinal(ByteBuffer, ByteBuffer) variant
+        buffer = new byte[Math.max(inputEndIndexInBuffer, outputEndIndexInBuffer)];
+        System.arraycopy(input, 0, buffer, inputOffsetInBuffer, input.length);
+        ByteBuffer inputBuffer = ByteBuffer.wrap(buffer, inputOffsetInBuffer, input.length);
+        ByteBuffer outputBuffer =
+                ByteBuffer.wrap(buffer, outputOffsetInBuffer, expectedOutput.length);
+        createCipher();
+        initKat(opmode);
+        assertEquals(expectedOutput.length, doFinal(inputBuffer, outputBuffer));
+        assertEquals(expectedOutput,
+                subarray(buffer, outputOffsetInBuffer, outputEndIndexInBuffer));
+    }
+
+    private void createCipher() throws NoSuchAlgorithmException,
+            NoSuchPaddingException  {
+        mCipher = Cipher.getInstance(getTransformation());
+    }
+
+    private String getKeyAlgorithm() {
+        String transformation = getTransformation();
+        int delimiterIndex = transformation.indexOf('/');
+        if (delimiterIndex == -1) {
+            fail("Unexpected transformation: " + transformation);
+        }
+        return transformation.substring(0, delimiterIndex);
+    }
+
+    private String getBlockMode() {
+        String transformation = getTransformation();
+        int delimiterIndex = transformation.indexOf('/');
+        if (delimiterIndex == -1) {
+            fail("Unexpected transformation: " + transformation);
+        }
+        int nextDelimiterIndex = transformation.indexOf('/', delimiterIndex + 1);
+        if (nextDelimiterIndex == -1) {
+            fail("Unexpected transformation: " + transformation);
+        }
+        return transformation.substring(delimiterIndex + 1, nextDelimiterIndex);
+    }
+
+    private String getPadding() {
+        String transformation = getTransformation();
+        int delimiterIndex = transformation.indexOf('/');
+        if (delimiterIndex == -1) {
+            fail("Unexpected transformation: " + transformation);
+        }
+        int nextDelimiterIndex = transformation.indexOf('/', delimiterIndex + 1);
+        if (nextDelimiterIndex == -1) {
+            fail("Unexpected transformation: " + transformation);
+        }
+        return transformation.substring(nextDelimiterIndex + 1);
+    }
+
+    private SecretKey getKey() {
+        return importKey(getKatKey());
+    }
+
+    private SecretKey importKey(byte[] keyMaterial) {
+        try {
+            int keyId = mNextKeyId++;
+            String keyAlias = "key" + keyId;
+            mAndroidKeyStore.setEntry(
+                    keyAlias,
+                    new KeyStore.SecretKeyEntry(new SecretKeySpec(keyMaterial, getKeyAlgorithm())),
+                    new KeyProtection.Builder(
+                            KeyProperties.PURPOSE_ENCRYPT
+                                    | KeyProperties.PURPOSE_DECRYPT)
+                            .setBlockModes(getBlockMode())
+                            .setEncryptionPaddings(getPadding())
+                            .setRandomizedEncryptionRequired(false)
+                            .build());
+            return (SecretKey) mAndroidKeyStore.getKey(keyAlias, null);
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to import key into AndroidKeyStore", e);
+        }
+    }
+
+    private boolean isPaddingEnabled() {
+        return !getTransformation().toLowerCase(Locale.US).endsWith("/nopadding");
+    }
+
+    private int getExpectedCiphertextLength(int plaintextLength) {
+        int blockSize = getBlockSize();
+        if (isStreamCipher()) {
+            // Padding not supported for stream ciphers
+            assertFalse(isPaddingEnabled());
+            return plaintextLength;
+        } else {
+            if (isPaddingEnabled()) {
+                return ((plaintextLength / blockSize) + 1) * blockSize;
+            } else {
+                return ((plaintextLength + blockSize - 1) / blockSize) * blockSize;
+            }
+        }
+    }
+
+    private void initKat(int opmode)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        init(opmode, getKey(), getKatAlgorithmParameterSpec());
+    }
+
+    private void init(int opmode, Key key, AlgorithmParameters spec)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        mCipher.init(opmode, key, spec);
+        mOpmode = opmode;
+    }
+
+    private void init(int opmode, Key key, AlgorithmParameters spec, SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        mCipher.init(opmode, key, spec, random);
+        mOpmode = opmode;
+    }
+
+    private void init(int opmode, Key key, AlgorithmParameterSpec spec)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        mCipher.init(opmode, key, spec);
+        mOpmode = opmode;
+    }
+
+    private void init(int opmode, Key key, AlgorithmParameterSpec spec, SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        mCipher.init(opmode, key, spec, random);
+        mOpmode = opmode;
+    }
+
+    private void init(int opmode, Key key) throws InvalidKeyException {
+        mCipher.init(opmode, key);
+        mOpmode = opmode;
+    }
+
+    private void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException {
+        mCipher.init(opmode, key, random);
+        mOpmode = opmode;
+    }
+
+    private byte[] doFinal() throws IllegalBlockSizeException, BadPaddingException {
+        return mCipher.doFinal();
+    }
+
+    private byte[] doFinal(byte[] input) throws IllegalBlockSizeException, BadPaddingException {
+        return mCipher.doFinal(input);
+    }
+
+    private byte[] doFinal(byte[] input, int inputOffset, int inputLen)
+            throws IllegalBlockSizeException, BadPaddingException {
+        return mCipher.doFinal(input, inputOffset, inputLen);
+    }
+
+    private int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output)
+            throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
+        return mCipher.doFinal(input, inputOffset, inputLen, output);
+    }
+
+    private int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output,
+            int outputOffset) throws ShortBufferException, IllegalBlockSizeException,
+            BadPaddingException {
+        return mCipher.doFinal(input, inputOffset, inputLen, output, outputOffset);
+    }
+
+    private int doFinal(byte[] output, int outputOffset) throws IllegalBlockSizeException,
+            ShortBufferException, BadPaddingException {
+        return mCipher.doFinal(output, outputOffset);
+    }
+
+    private int doFinal(ByteBuffer input, ByteBuffer output) throws ShortBufferException,
+            IllegalBlockSizeException, BadPaddingException {
+        return mCipher.doFinal(input, output);
+    }
+
+    private boolean isEncrypting() {
+        return (mOpmode == Cipher.ENCRYPT_MODE) || (mOpmode == Cipher.WRAP_MODE);
+    }
+
+    private void assertUpdateOutputSize(int inputLength, int outputLength) {
+        if ((isAuthenticatedCipher()) && (!isEncrypting())) {
+            assertEquals("Output of update must be empty for authenticated cipher when decrypting",
+                    0, outputLength);
+            return;
+        }
+
+        if (isStreamCipher()) {
+            if (outputLength != inputLength) {
+                fail("Output of update (" + outputLength + ") not same size as input ("
+                        + inputLength + ")");
+            }
+        } else {
+            if ((outputLength % getBlockSize()) != 0) {
+                fail("Output of update (" + outputLength + ") not a multiple of block size ("
+                        + getBlockSize() + ")");
+            }
+        }
+    }
+
+    private byte[] update(byte[] input) {
+        byte[] output = mCipher.update(input);
+        assertUpdateOutputSize(
+                (input != null) ? input.length : 0, (output != null) ? output.length : 0);
+        return output;
+    }
+
+    private byte[] update(byte[] input, int offset, int len) {
+        byte[] output = mCipher.update(input, offset, len);
+        assertUpdateOutputSize(len, (output != null) ? output.length : 0);
+
+        return output;
+    }
+
+    private int update(byte[] input, int offset, int len, byte[] output)
+            throws ShortBufferException {
+        int outputLen = mCipher.update(input, offset, len, output);
+        assertUpdateOutputSize(len, outputLen);
+
+        return outputLen;
+    }
+
+    private int update(byte[] input, int offset, int len, byte[] output, int outputOffset)
+            throws ShortBufferException {
+        int outputLen = mCipher.update(input, offset, len, output, outputOffset);
+        assertUpdateOutputSize(len, outputLen);
+
+        return outputLen;
+    }
+
+    private int update(ByteBuffer input, ByteBuffer output) throws ShortBufferException {
+        int inputLimitBefore = input.limit();
+        int outputLimitBefore = output.limit();
+        int inputLen = input.remaining();
+        int outputPosBefore = output.position();
+
+        int outputLen = mCipher.update(input, output);
+
+        assertUpdateOutputSize(inputLen, outputLen);
+        assertEquals(inputLimitBefore, input.limit());
+        assertEquals(input.limit(), input.position());
+
+        assertEquals(outputLimitBefore, output.limit());
+        assertEquals(outputPosBefore + outputLen, output.position());
+
+        return outputLen;
+    }
+
+    @SuppressWarnings("unused")
+    private static void assertEquals(Buffer expected, Buffer actual) {
+        throw new RuntimeException(
+                "Comparing ByteBuffers using their .equals is probably not what you want"
+                + " -- use assertByteBufferEquals instead.");
+    }
+
+    /**
+     * Asserts that the position, limit, and capacity of the provided buffers are the same, and that
+     * their contents (from position {@code 0} to capacity) are the same.
+     */
+    private static void assertByteBufferEquals(ByteBuffer expected, ByteBuffer actual) {
+        if (expected == null) {
+            if (actual == null) {
+                return;
+            } else {
+                fail("Expected: null, actual: " + bufferToString(actual));
+            }
+        } else {
+            if (actual == null) {
+                fail("Expected: " + bufferToString(expected) + ", actual: null");
+            } else {
+                if ((expected.capacity() != actual.capacity())
+                        || (expected.position() != actual.position())
+                        || (expected.limit() != actual.limit())
+                        || (!equals(expected.array(), expected.arrayOffset(), expected.capacity(),
+                                    actual.array(), actual.arrayOffset(), actual.capacity()))) {
+                    fail("Expected: " + bufferToString(expected)
+                            + ", actual: " + bufferToString(actual));
+                }
+            }
+        }
+    }
+
+    private static String bufferToString(ByteBuffer buffer) {
+        return "ByteBuffer[pos: " + buffer.position() + ", limit: " + buffer.limit()
+                + ", capacity: " + buffer.capacity()
+                + ", backing array: " + HexEncoding.encode(
+                        buffer.array(), buffer.arrayOffset(), buffer.capacity()) + "]";
+    }
+
+    private static boolean equals(byte[] arr1, int offset1, int len1, byte[] arr2, int offset2,
+            int len2) {
+        if (arr1 == null) {
+            return (arr2 == null);
+        } else if (arr2 == null) {
+            return (arr1 == null);
+        } else {
+            if (len1 != len2) {
+                return false;
+            }
+            for (int i = 0; i < len1; i++) {
+                if (arr1[i + offset1] != arr2[i + offset2]) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    private static byte[] subarray(byte[] array, int beginIndex, int endIndex) {
+        byte[] result = new byte[endIndex - beginIndex];
+        System.arraycopy(array, beginIndex, result, 0, result.length);
+        return result;
+    }
+
+    private static byte[] concat(byte[]... arrays) {
+        int resultLength = 0;
+        for (byte[] array : arrays) {
+            resultLength += (array != null) ? array.length : 0;
+        }
+
+        byte[] result = new byte[resultLength];
+        int resultOffset = 0;
+        for (byte[] array : arrays) {
+            if (array != null) {
+                System.arraycopy(array, 0, result, resultOffset, array.length);
+                resultOffset += array.length;
+            }
+        }
+        return result;
+    }
+
+    private static void assertEquals(byte[] expected, byte[] actual) {
+        assertEquals(null, expected, actual);
+    }
+
+    private static void assertEquals(String message, byte[] expected, byte[] actual) {
+        if (!Arrays.equals(expected, actual)) {
+            StringBuilder detail = new StringBuilder();
+            if (expected != null) {
+                detail.append("Expected (" + expected.length + " bytes): <"
+                        + HexEncoding.encode(expected) + ">");
+            } else {
+                detail.append("Expected: null");
+            }
+            if (actual != null) {
+                detail.append(", actual (" + actual.length + " bytes): <"
+                        + HexEncoding.encode(actual) + ">");
+            } else {
+                detail.append(", actual: null");
+            }
+            if (message != null) {
+                fail(message + ": " + detail);
+            } else {
+                fail(detail.toString());
+            }
+        }
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/CountingSecureRandom.java b/tests/tests/keystore/src/android/keystore/cts/CountingSecureRandom.java
index a93cc35..ea4d0d1 100644
--- a/tests/tests/keystore/src/android/keystore/cts/CountingSecureRandom.java
+++ b/tests/tests/keystore/src/android/keystore/cts/CountingSecureRandom.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.keystore.cts;
 
 import java.security.SecureRandom;
diff --git a/tests/tests/keystore/src/android/keystore/cts/EmptyArray.java b/tests/tests/keystore/src/android/keystore/cts/EmptyArray.java
new file mode 100644
index 0000000..90ac2c4
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/EmptyArray.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+abstract class EmptyArray {
+    private EmptyArray() {}
+
+    public static final byte[] BYTE = new byte[0];
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyPairGeneratorTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyPairGeneratorTest.java
index db7f539..e3540b4 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyPairGeneratorTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyPairGeneratorTest.java
@@ -40,6 +40,7 @@
 import java.security.interfaces.ECKey;
 import java.security.interfaces.ECPublicKey;
 import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.ECGenParameterSpec;
 import java.security.spec.ECParameterSpec;
 import java.security.spec.RSAKeyGenParameterSpec;
@@ -354,7 +355,7 @@
                             | KeyProperties.PURPOSE_ENCRYPT
                             | KeyProperties.PURPOSE_DECRYPT)
                     .setDigests(KeyProperties.DIGEST_NONE)
-                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
                     .setCertificateSubject(TEST_DN_1)
                     .setCertificateSerialNumber(TEST_SERIAL_1)
                     .setCertificateNotBefore(NOW)
@@ -381,7 +382,7 @@
                             | KeyProperties.PURPOSE_ENCRYPT
                             | KeyProperties.PURPOSE_DECRYPT)
                     .setDigests(KeyProperties.DIGEST_NONE)
-                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
                     .setCertificateSubject(TEST_DN_2)
                     .setCertificateSerialNumber(TEST_SERIAL_2)
                     .setCertificateNotBefore(NOW)
@@ -410,7 +411,7 @@
                         | KeyProperties.PURPOSE_ENCRYPT
                         | KeyProperties.PURPOSE_DECRYPT)
                 .setDigests(KeyProperties.DIGEST_NONE)
-                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
                 .setCertificateSubject(TEST_DN_1)
                 .setCertificateSerialNumber(TEST_SERIAL_1)
                 .setCertificateNotBefore(NOW)
@@ -435,7 +436,7 @@
                         | KeyProperties.PURPOSE_ENCRYPT
                         | KeyProperties.PURPOSE_DECRYPT)
                 .setDigests(KeyProperties.DIGEST_NONE)
-                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
                 .setCertificateSubject(TEST_DN_2)
                 .setCertificateSerialNumber(TEST_SERIAL_2)
                 .setCertificateNotBefore(NOW)
@@ -839,6 +840,75 @@
                 2048, RSAKeyGenParameterSpec.F0));
     }
 
+    public void testGenerate_RSA_IndCpaEnforced() throws Exception {
+        KeyGenParameterSpec.Builder goodBuilder = new KeyGenParameterSpec.Builder(
+                TEST_ALIAS_1, KeyProperties.PURPOSE_ENCRYPT)
+                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP,
+                        KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1);
+        assertKeyGenInitSucceeds("RSA", goodBuilder.build());
+
+        // Should be fine because IND-CPA restriction applies only to encryption keys
+        assertKeyGenInitSucceeds("RSA",
+                TestUtils.buildUpon(goodBuilder, KeyProperties.PURPOSE_DECRYPT)
+                        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                        .build());
+
+        assertKeyGenInitThrowsInvalidAlgorithmParameterException("RSA",
+                TestUtils.buildUpon(goodBuilder)
+                        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                        .build());
+
+        assertKeyGenInitSucceeds("RSA",
+                TestUtils.buildUpon(goodBuilder)
+                        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                        .setRandomizedEncryptionRequired(false)
+                        .build());
+
+        // Should fail because PKCS#7 padding doesn't work with RSA
+        assertKeyGenInitThrowsInvalidAlgorithmParameterException("RSA",
+                TestUtils.buildUpon(goodBuilder)
+                        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
+                        .build());
+    }
+
+    public void testGenerate_EC_IndCpaEnforced() throws Exception {
+        KeyGenParameterSpec.Builder goodBuilder = new KeyGenParameterSpec.Builder(
+                TEST_ALIAS_2, KeyProperties.PURPOSE_ENCRYPT);
+        assertKeyGenInitSucceeds("EC", goodBuilder.build());
+
+        // Should be fine because IND-CPA restriction applies only to encryption keys
+        assertKeyGenInitSucceeds("EC",
+                TestUtils.buildUpon(goodBuilder, KeyProperties.PURPOSE_DECRYPT)
+                        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                        .build());
+
+        assertKeyGenInitThrowsInvalidAlgorithmParameterException("EC",
+                TestUtils.buildUpon(goodBuilder)
+                        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                        .build());
+
+        assertKeyGenInitSucceeds("EC",
+                TestUtils.buildUpon(goodBuilder)
+                        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                        .setRandomizedEncryptionRequired(false)
+                        .build());
+    }
+
+    private void assertKeyGenInitSucceeds(String algorithm, AlgorithmParameterSpec params)
+            throws Exception {
+        KeyPairGenerator generator = getGenerator(algorithm);
+        generator.initialize(params);
+    }
+
+    private void assertKeyGenInitThrowsInvalidAlgorithmParameterException(
+            String algorithm, AlgorithmParameterSpec params) throws Exception {
+        KeyPairGenerator generator = getGenerator(algorithm);
+        try {
+            generator.initialize(params);
+            fail();
+        } catch (InvalidAlgorithmParameterException expected) {}
+    }
+
     private void assertKeyGenUsingECSizeOnlyUsesCorrectCurve(
             int keySizeBits, ECParameterSpec expectedParams) throws Exception {
         KeyPairGenerator generator = getEcGenerator();
@@ -1161,12 +1231,17 @@
 
     private KeyPairGenerator getRsaGenerator()
             throws NoSuchAlgorithmException, NoSuchProviderException {
-        return KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
+        return getGenerator("RSA");
     }
 
     private KeyPairGenerator getEcGenerator()
             throws NoSuchAlgorithmException, NoSuchProviderException {
-        return KeyPairGenerator.getInstance("EC", "AndroidKeyStore");
+        return getGenerator("EC");
+    }
+
+    private KeyPairGenerator getGenerator(String algorithm)
+            throws NoSuchAlgorithmException, NoSuchProviderException {
+        return KeyPairGenerator.getInstance(algorithm, "AndroidKeyStore");
     }
 
     private static void assertOneOf(int actual, int... expected) {
diff --git a/tests/tests/keystore/src/android/keystore/cts/MacTest.java b/tests/tests/keystore/src/android/keystore/cts/MacTest.java
new file mode 100644
index 0000000..d654e3a
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/MacTest.java
@@ -0,0 +1,367 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.keystore.cts;
+
+import android.security.keystore.KeyProperties;
+import android.security.keystore.KeyProtection;
+
+import junit.framework.TestCase;
+
+import java.security.InvalidKeyException;
+import java.security.Provider;
+import java.security.Provider.Service;
+import java.security.Security;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+public class MacTest extends TestCase {
+
+    private static final String EXPECTED_PROVIDER_NAME = TestUtils.EXPECTED_CRYPTO_OP_PROVIDER_NAME;
+
+    private static final String[] EXPECTED_ALGORITHMS = {
+        "HmacSHA1",
+        "HmacSHA224",
+        "HmacSHA256",
+        "HmacSHA384",
+        "HmacSHA512",
+    };
+
+    private static final byte[] KAT_KEY = HexEncoding.decode(
+            "227b212bebd775493929ef626729a587d3f81b8e18a3ed482d403910e184479b448cfa79b62bd90595efdd"
+            + "15f87bd7b2d2dac480c61e969ba90a7b8ceadd3284");
+
+    private static final byte[] SHORT_MSG_KAT_MESSAGE = HexEncoding.decode("a16037e3c901c9a1ab");
+
+    private static final Map<String, byte[]> SHORT_MSG_KAT_MACS =
+            new TreeMap<String, byte[]>(String.CASE_INSENSITIVE_ORDER);
+    static {
+        // From RI
+        SHORT_MSG_KAT_MACS.put("HmacSHA1", HexEncoding.decode(
+                "47d5677267f0efe1f7416bf504b210765674ef50"));
+        SHORT_MSG_KAT_MACS.put("HmacSHA224", HexEncoding.decode(
+                "03a8bbcd05e7166bff5b0b2368709a0c61c0b9d94f1b4d65c0e04948"));
+        SHORT_MSG_KAT_MACS.put("HmacSHA256", HexEncoding.decode(
+                "17feed3de0b2d53b69b228c2d9d26e9d57b314c50d36662596777f49445df729"));
+        SHORT_MSG_KAT_MACS.put("HmacSHA384", HexEncoding.decode(
+                "26e034c6696d28722ffc446ff0994f835e616cc704517d283a29648aee1eca5569c792ada8a176cdc7"
+                + "813a87437e4ea0"));
+        SHORT_MSG_KAT_MACS.put("HmacSHA512", HexEncoding.decode(
+                "15cff189d754d6612bd18d157c8e59ac2ecd9a4b97b2ef343b7778130f7741795d5d2dc2b7addb9a36"
+                + "7677ad57833b42bfa0733f49b57afd6bc32cddc0dcebec"));
+    }
+
+    private static final byte[] LONG_MSG_KAT_SEED = SHORT_MSG_KAT_MESSAGE;
+    private static final int LONG_MSG_KAT_SIZE_BYTES = 3 * 1024 * 1024 + 149;
+
+    private static final Map<String, byte[]> LONG_MSG_KAT_MACS =
+            new TreeMap<String, byte[]>(String.CASE_INSENSITIVE_ORDER);
+    static {
+        // From RI
+        LONG_MSG_KAT_MACS.put("HmacSHA1", HexEncoding.decode(
+                "2a89d12da79f541512db9c35c0a1e76750e01d48"));
+        LONG_MSG_KAT_MACS.put("HmacSHA224", HexEncoding.decode(
+                "5fef55c822f9b931c1b4ad7142e0a74ceaddf03f0a6533155cc06871"));
+        LONG_MSG_KAT_MACS.put("HmacSHA256", HexEncoding.decode(
+                "0bc25f22b8993d003a95a88c6cfa1c5a7b067a8aae1064ef897712418569bfe9"));
+        LONG_MSG_KAT_MACS.put("HmacSHA384", HexEncoding.decode(
+                "595a616295123966126102c06d69f8bb06c11090490186243420c2c4692877d75752b220c1b0447320"
+                + "959e28345523fc"));
+        LONG_MSG_KAT_MACS.put("HmacSHA512", HexEncoding.decode(
+                "aa97d594d799164d56e6652578f7884d1198bb2663641ad7903e3c0bda4c136e9f94ca0d16c3504302"
+                + "2944224e538e88a5410adb38eaa5169b3125738990e6d0"));
+    }
+
+
+    private static final long DAY_IN_MILLIS = 1000 * 60 * 60 * 24;
+
+    public void testAlgorithmList() {
+        // Assert that Android Keystore Provider exposes exactly the expected MAC algorithms. We
+        // don't care whether the algorithms are exposed via aliases, as long as the canonical names
+        // of algorithms are accepted.
+        // If the Provider exposes extraneous algorithms, it'll be caught because it'll have to
+        // expose at least one Service for such an algorithm, and this Service's algorithm will
+        // not be in the expected set.
+
+        Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME);
+        Set<Service> services = provider.getServices();
+        Set<String> actualAlgsLowerCase = new HashSet<String>();
+        Set<String> expectedAlgsLowerCase = new HashSet<String>(
+                Arrays.asList(TestUtils.toLowerCase(EXPECTED_ALGORITHMS)));
+        for (Service service : services) {
+            if ("Mac".equalsIgnoreCase(service.getType())) {
+                String algLowerCase = service.getAlgorithm().toLowerCase(Locale.US);
+                actualAlgsLowerCase.add(algLowerCase);
+            }
+        }
+
+        TestUtils.assertContentsInAnyOrder(actualAlgsLowerCase,
+                expectedAlgsLowerCase.toArray(new String[0]));
+    }
+
+    public void testAndroidKeyStoreKeysHandledByAndroidKeyStoreProvider() throws Exception {
+        SecretKey key = importDefaultKatKey();
+        Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME);
+        assertNotNull(provider);
+        for (String algorithm : EXPECTED_ALGORITHMS) {
+            try {
+                // Generate a MAC
+                Mac mac = Mac.getInstance(algorithm);
+                mac.init(key);
+                assertSame(provider, mac.getProvider());
+            } catch (Exception e) {
+                throw new RuntimeException(algorithm + " failed", e);
+            }
+        }
+    }
+
+    public void testGeneratedSignatureVerifies() throws Exception {
+        SecretKey key = importDefaultKatKey();
+
+        Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME);
+        assertNotNull(provider);
+        for (String algorithm : EXPECTED_ALGORITHMS) {
+            try {
+                // Generate a MAC
+                Mac mac = Mac.getInstance(algorithm);
+                mac.init(key);
+                byte[] message = "This is a test".getBytes("UTF-8");
+                byte[] macBytes = mac.doFinal(message);
+
+                assertMacVerifiesOneShot(algorithm, key, message, macBytes);
+            } catch (Exception e) {
+                throw new RuntimeException(algorithm + " failed", e);
+            }
+        }
+    }
+
+    public void testSmallMsgKat() throws Exception {
+        SecretKey key = importDefaultKatKey();
+        byte[] message = SHORT_MSG_KAT_MESSAGE;
+
+        for (String algorithm : EXPECTED_ALGORITHMS) {
+            try {
+                byte[] goodMacBytes = SHORT_MSG_KAT_MACS.get(algorithm);
+                assertNotNull(goodMacBytes);
+                assertMacVerifiesOneShot(algorithm, key, message, goodMacBytes);
+                assertMacVerifiesFedOneByteAtATime(algorithm, key, message, goodMacBytes);
+                assertMacVerifiesFedUsingFixedSizeChunks(algorithm, key, message, goodMacBytes, 3);
+
+                byte[] messageWithBitFlip = message.clone();
+                messageWithBitFlip[messageWithBitFlip.length / 2] ^= 1;
+                assertMacDoesNotVerifyOneShot(algorithm, key, messageWithBitFlip, goodMacBytes);
+
+                byte[] goodMacWithBitFlip = goodMacBytes.clone();
+                goodMacWithBitFlip[goodMacWithBitFlip.length / 2] ^= 1;
+                assertMacDoesNotVerifyOneShot(algorithm, key, message, goodMacWithBitFlip);
+            } catch (Throwable e) {
+                throw new RuntimeException("Failed for " + algorithm, e);
+            }
+        }
+    }
+
+    public void testLargeMsgKat() throws Exception {
+        SecretKey key = importDefaultKatKey();
+        byte[] message = TestUtils.generateLargeKatMsg(LONG_MSG_KAT_SEED, LONG_MSG_KAT_SIZE_BYTES);
+
+        for (String algorithm : EXPECTED_ALGORITHMS) {
+            try {
+                byte[] goodMacBytes = LONG_MSG_KAT_MACS.get(algorithm);
+                assertNotNull(goodMacBytes);
+                assertMacVerifiesOneShot(algorithm,  key, message, goodMacBytes);
+                assertMacVerifiesFedUsingFixedSizeChunks(
+                        algorithm, key, message, goodMacBytes, 20389);
+                assertMacVerifiesFedUsingFixedSizeChunks(
+                        algorithm, key, message, goodMacBytes, 393571);
+            } catch (Throwable e) {
+                throw new RuntimeException("Failed for " + algorithm, e);
+            }
+        }
+    }
+
+    public void testInitFailsWhenNotAuthorizedToSign() throws Exception {
+        KeyProtection.Builder good = new KeyProtection.Builder(KeyProperties.PURPOSE_SIGN);
+        int badPurposes = KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT
+                | KeyProperties.PURPOSE_VERIFY;
+        String algorithm = "HmacSHA512";
+        assertInitSucceeds(algorithm, algorithm, good.build());
+        assertInitThrowsInvalidKeyException(algorithm, algorithm,
+                TestUtils.buildUpon(good, badPurposes).build());
+    }
+
+    public void testInitFailsWhenDigestNotAuthorized() throws Exception {
+        KeyProtection spec = new KeyProtection.Builder(KeyProperties.PURPOSE_SIGN).build();
+        assertInitSucceeds("HmacSHA384", "HmacSHA384", spec);
+        assertInitThrowsInvalidKeyException("HmacSHA256", "HmacSHA384", spec);
+    }
+
+    public void testInitFailsWhenKeyNotYetValid() throws Exception {
+        KeyProtection.Builder good = new KeyProtection.Builder(
+                KeyProperties.PURPOSE_SIGN)
+                .setKeyValidityStart(new Date(System.currentTimeMillis() - DAY_IN_MILLIS));
+        String algorithm = "HmacSHA224";
+        assertInitSucceeds(algorithm, algorithm, good.build());
+
+        Date badStartDate = new Date(System.currentTimeMillis() + DAY_IN_MILLIS);
+        assertInitThrowsInvalidKeyException(algorithm, algorithm,
+                TestUtils.buildUpon(good).setKeyValidityStart(badStartDate).build());
+    }
+
+    public void testInitFailsWhenKeyNoLongerValid() throws Exception {
+        KeyProtection.Builder good = new KeyProtection.Builder(
+                KeyProperties.PURPOSE_SIGN)
+                .setKeyValidityForOriginationEnd(
+                        new Date(System.currentTimeMillis() + DAY_IN_MILLIS));
+        String algorithm = "HmacSHA1";
+        assertInitSucceeds(algorithm, algorithm, good.build());
+
+        Date badEndDate = new Date(System.currentTimeMillis() - DAY_IN_MILLIS);
+        assertInitThrowsInvalidKeyException(algorithm, algorithm,
+                TestUtils.buildUpon(good).setKeyValidityForOriginationEnd(badEndDate).build());
+    }
+
+    private void assertMacVerifiesOneShot(
+            String algorithm,
+            SecretKey key,
+            byte[] message,
+            byte[] mac) throws Exception {
+        Mac m = Mac.getInstance(algorithm);
+        m.init(key);
+        byte[] mac2 = m.doFinal(message);
+        if (!Arrays.equals(mac, mac2)) {
+            fail("MAC did not verify. algorithm: " + algorithm
+                    + ", provider: " + m.getProvider().getName()
+                    + ", MAC (" + mac.length + " bytes): " + HexEncoding.encode(mac)
+                    + ", actual MAC (" + mac2.length + " bytes): " + HexEncoding.encode(mac2));
+        }
+    }
+
+    private void assertMacDoesNotVerifyOneShot(
+            String algorithm,
+            SecretKey key,
+            byte[] message,
+            byte[] mac) throws Exception {
+        Mac m = Mac.getInstance(algorithm);
+        m.init(key);
+        byte[] mac2 = m.doFinal(message);
+        if (Arrays.equals(mac, mac2)) {
+            fail("MAC verifies unexpectedly. algorithm: " + algorithm
+                    + ", provider: " + m.getProvider().getName()
+                    + ", MAC (" + mac.length + " bytes): " + HexEncoding.encode(mac));
+        }
+    }
+
+
+    private void assertMacVerifiesFedOneByteAtATime(
+            String algorithm,
+            SecretKey key,
+            byte[] message,
+            byte[] mac) throws Exception {
+        Mac m = Mac.getInstance(algorithm);
+        m.init(key);
+        for (int i = 0; i < message.length; i++) {
+            m.update(message[i]);
+        }
+        byte[] mac2 = m.doFinal();
+        if (!Arrays.equals(mac, mac2)) {
+            fail("MAC did not verify. algorithm: " + algorithm
+                    + ", provider: " + m.getProvider().getName()
+                    + ", MAC (" + mac.length + " bytes): " + HexEncoding.encode(mac)
+                    + ", actual MAC (" + mac2.length + " bytes): " + HexEncoding.encode(mac2));
+        }
+    }
+
+    private void assertMacVerifiesFedUsingFixedSizeChunks(
+            String algorithm,
+            SecretKey key,
+            byte[] message,
+            byte[] mac,
+            int chunkSizeBytes) throws Exception {
+        Mac m = Mac.getInstance(algorithm);
+        m.init(key);
+        int messageRemaining = message.length;
+        int messageOffset = 0;
+        while (messageRemaining > 0) {
+            int actualChunkSizeBytes =  Math.min(chunkSizeBytes, messageRemaining);
+            m.update(message, messageOffset, actualChunkSizeBytes);
+            messageOffset += actualChunkSizeBytes;
+            messageRemaining -= actualChunkSizeBytes;
+        }
+        byte[] mac2 = m.doFinal();
+        if (!Arrays.equals(mac, mac2)) {
+            fail("MAC did not verify. algorithm: " + algorithm
+                    + ", provider: " + m.getProvider().getName()
+                    + ", MAC (" + mac.length + " bytes): " + HexEncoding.encode(mac)
+                    + ", actual MAC (" + mac2.length + " bytes): " + HexEncoding.encode(mac2));
+        }
+    }
+
+    private void assertInitSucceeds(
+            String macAlgorithm, String keyAlgorithm, KeyProtection keyProtection)
+                    throws Exception {
+        SecretKey key = importDefaultKatKey(keyAlgorithm, keyProtection);
+        Mac mac = Mac.getInstance(macAlgorithm);
+        mac.init(key);
+    }
+
+    private void assertInitThrowsInvalidKeyException(
+            String macAlgorithm, String keyAlgorithm, KeyProtection keyProtection)
+                    throws Exception {
+        assertInitThrowsInvalidKeyException(null, macAlgorithm, keyAlgorithm, keyProtection);
+    }
+
+
+    private void assertInitThrowsInvalidKeyException(
+            String message, String macAlgorithm, String keyAlgorithm,
+            KeyProtection keyProtection) throws Exception {
+        SecretKey key = importDefaultKatKey(keyAlgorithm, keyProtection);
+        Mac mac = Mac.getInstance(macAlgorithm);
+        try {
+            mac.init(key);
+            fail(message);
+        } catch (InvalidKeyException expected) {}
+    }
+
+    private SecretKey importDefaultKatKey() throws Exception {
+        return importDefaultKatKey("HmacSHA1",
+                new KeyProtection.Builder(
+                        KeyProperties.PURPOSE_SIGN)
+                        .setDigests(KeyProperties.DIGEST_NONE,
+                                KeyProperties.DIGEST_SHA1, // TODO: Remove these digests
+                                KeyProperties.DIGEST_SHA224,
+                                KeyProperties.DIGEST_SHA256,
+                                KeyProperties.DIGEST_SHA384,
+                                KeyProperties.DIGEST_SHA512)
+                        .build());
+    }
+
+    private SecretKey importDefaultKatKey(
+            String keyAlgorithm, KeyProtection keyProtection) throws Exception {
+        return TestUtils.importIntoAndroidKeyStore(
+                "test1",
+                new SecretKeySpec(KAT_KEY, keyAlgorithm),
+                keyProtection);
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/SignatureTest.java b/tests/tests/keystore/src/android/keystore/cts/SignatureTest.java
index 9e8678b..c53e2c3 100644
--- a/tests/tests/keystore/src/android/keystore/cts/SignatureTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/SignatureTest.java
@@ -20,7 +20,6 @@
 
 import java.security.InvalidKeyException;
 import java.security.KeyPair;
-import java.security.MessageDigest;
 import java.security.PrivateKey;
 import java.security.Provider;
 import java.security.Provider.Service;
@@ -43,7 +42,8 @@
 import android.test.MoreAsserts;
 
 public class SignatureTest extends AndroidTestCase {
-    static final String EXPECTED_PROVIDER_NAME = "AndroidKeyStoreBCWorkaround";
+
+    static final String EXPECTED_PROVIDER_NAME = TestUtils.EXPECTED_CRYPTO_OP_PROVIDER_NAME;
 
     private static final String[] EXPECTED_SIGNATURE_ALGORITHMS = {
         "NONEwithRSA",
@@ -487,24 +487,9 @@
         }
     }
 
-    private static byte[] generateLargeKatMsg(byte[] seed, int msgSizeBytes) throws Exception {
-        byte[] result = new byte[msgSizeBytes];
-        MessageDigest digest = MessageDigest.getInstance("SHA-512");
-        int resultOffset = 0;
-        int resultRemaining = msgSizeBytes;
-        while (resultRemaining > 0) {
-            seed = digest.digest(seed);
-            int chunkSize = Math.min(seed.length, resultRemaining);
-            System.arraycopy(seed, 0, result, resultOffset, chunkSize);
-            resultOffset += chunkSize;
-            resultRemaining -= chunkSize;
-        }
-        return result;
-    }
-
     public void testLongMsgKat() throws Exception {
         Collection<KeyPair> keyPairs = importDefaultKatKeyPairs();
-        byte[] message = generateLargeKatMsg(LONG_MSG_KAT_SEED, LONG_MSG_KAT_SIZE_BYTES);
+        byte[] message = TestUtils.generateLargeKatMsg(LONG_MSG_KAT_SEED, LONG_MSG_KAT_SIZE_BYTES);
 
         Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME);
         assertNotNull(provider);
@@ -952,6 +937,7 @@
         }
         return signature.sign();
     }
+
     private void assertSignatureVerifiesFedUsingFixedSizeChunks(
             String algorithm,
             Provider provider,
diff --git a/tests/tests/keystore/src/android/keystore/cts/TestUtils.java b/tests/tests/keystore/src/android/keystore/cts/TestUtils.java
index 02fbd1e..3448ffc 100644
--- a/tests/tests/keystore/src/android/keystore/cts/TestUtils.java
+++ b/tests/tests/keystore/src/android/keystore/cts/TestUtils.java
@@ -33,6 +33,7 @@
 import java.security.KeyPairGenerator;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
+import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;
 import java.security.PrivateKey;
@@ -62,6 +63,10 @@
 import javax.crypto.spec.SecretKeySpec;
 
 abstract class TestUtils extends Assert {
+
+    static final String EXPECTED_CRYPTO_OP_PROVIDER_NAME = "AndroidKeyStoreBCWorkaround";
+
+
     private TestUtils() {}
 
     /**
@@ -417,6 +422,18 @@
                 (PrivateKey) keyStore.getKey(alias, null));
     }
 
+    static SecretKey importIntoAndroidKeyStore(
+            String alias,
+            SecretKey key,
+            KeyProtection keyProtection) throws Exception {
+        KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+        keyStore.load(null);
+        keyStore.setEntry(alias,
+                new KeyStore.SecretKeyEntry(key),
+                keyProtection);
+        return (SecretKey) keyStore.getKey(alias, null);
+    }
+
     static byte[] drain(InputStream in) throws IOException {
         ByteArrayOutputStream result = new ByteArrayOutputStream();
         byte[] buffer = new byte[16 * 1024];
@@ -458,6 +475,48 @@
         return result;
     }
 
+    static KeyGenParameterSpec.Builder buildUpon(
+            KeyGenParameterSpec.Builder builder) {
+        return buildUponInternal(builder, null);
+    }
+
+    static KeyGenParameterSpec.Builder buildUpon(
+            KeyGenParameterSpec.Builder builder, int newPurposes) {
+        return buildUponInternal(builder, newPurposes);
+    }
+
+    private static KeyGenParameterSpec.Builder buildUponInternal(
+            KeyGenParameterSpec.Builder builder, Integer newPurposes) {
+        KeyGenParameterSpec spec = builder.build();
+        int purposes = (newPurposes == null) ? spec.getPurposes() : newPurposes;
+        KeyGenParameterSpec.Builder result =
+                new KeyGenParameterSpec.Builder(spec.getKeystoreAlias(), purposes);
+        if (spec.getKeySize() >= 0) {
+            result.setKeySize(spec.getKeySize());
+        }
+        if (spec.getAlgorithmParameterSpec() != null) {
+            result.setAlgorithmParameterSpec(spec.getAlgorithmParameterSpec());
+        }
+        result.setCertificateNotBefore(spec.getCertificateNotBefore());
+        result.setCertificateNotAfter(spec.getCertificateNotAfter());
+        result.setCertificateSerialNumber(spec.getCertificateSerialNumber());
+        result.setCertificateSubject(spec.getCertificateSubject());
+        result.setBlockModes(spec.getBlockModes());
+        if (spec.isDigestsSpecified()) {
+            result.setDigests(spec.getDigests());
+        }
+        result.setEncryptionPaddings(spec.getEncryptionPaddings());
+        result.setSignaturePaddings(spec.getSignaturePaddings());
+        result.setKeyValidityStart(spec.getKeyValidityStart());
+        result.setKeyValidityForOriginationEnd(spec.getKeyValidityForOriginationEnd());
+        result.setKeyValidityForConsumptionEnd(spec.getKeyValidityForConsumptionEnd());
+        result.setRandomizedEncryptionRequired(spec.isRandomizedEncryptionRequired());
+        result.setUserAuthenticationRequired(spec.isUserAuthenticationRequired());
+        result.setUserAuthenticationValidityDurationSeconds(
+                spec.getUserAuthenticationValidityDurationSeconds());
+        return result;
+    }
+
     static KeyPair getKeyPairForKeyAlgorithm(String keyAlgorithm, Iterable<KeyPair> keyPairs) {
         for (KeyPair keyPair : keyPairs) {
             if (keyAlgorithm.equalsIgnoreCase(keyPair.getPublic().getAlgorithm())) {
@@ -466,4 +525,19 @@
         }
         throw new IllegalArgumentException("No KeyPair for key algorithm " + keyAlgorithm);
     }
+
+    static byte[] generateLargeKatMsg(byte[] seed, int msgSizeBytes) throws Exception {
+        byte[] result = new byte[msgSizeBytes];
+        MessageDigest digest = MessageDigest.getInstance("SHA-512");
+        int resultOffset = 0;
+        int resultRemaining = msgSizeBytes;
+        while (resultRemaining > 0) {
+            seed = digest.digest(seed);
+            int chunkSize = Math.min(seed.length, resultRemaining);
+            System.arraycopy(seed, 0, result, resultOffset, chunkSize);
+            resultOffset += chunkSize;
+            resultRemaining -= chunkSize;
+        }
+        return result;
+    }
 }
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
index daf55a7..15438e8 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
@@ -587,6 +587,7 @@
     }
 
     public void testGetMaxSupportedInstances() {
+        StringBuilder xmlOverrides = new StringBuilder();
         MediaCodecList allCodecs = new MediaCodecList(MediaCodecList.ALL_CODECS);
         for (MediaCodecInfo info : allCodecs.getCodecInfos()) {
             Log.d(TAG, "codec: " + info.getName());
@@ -604,9 +605,25 @@
                     int actualMax = getActualMax(
                             info.isEncoder(), info.getName(), types[j], caps, max + 1);
                     Log.d(TAG, "actualMax " + actualMax + " vs reported max " + max);
-                    assertTrue(actualMax >= (int)(max * 0.9));
+                    if (actualMax < (int)(max * 0.9) || actualMax > (int) Math.ceil(max * 1.1)) {
+                        String codec = "<MediaCodec name=\"" + info.getName() +
+                                "\" type=\"" + types[j] + "\" >";
+                        String limit = "    <Limit name=\"concurrent-instances\" max=\"" +
+                                actualMax + "\" />";
+                        xmlOverrides.append(codec);
+                        xmlOverrides.append("\n");
+                        xmlOverrides.append(limit);
+                        xmlOverrides.append("\n");
+                        xmlOverrides.append("</MediaCodec>\n");
+                    }
                 }
             }
         }
+
+        if (xmlOverrides.length() > 0) {
+            String failMessage = "In order to pass the test, please publish following " +
+                    "codecs' concurrent instances limit in /etc/media_codecs.xml: \n";
+           fail(failMessage + xmlOverrides.toString());
+        }
     }
 }
diff --git a/tests/tests/media/src/android/media/cts/ResourceManagerStubActivity.java b/tests/tests/media/src/android/media/cts/ResourceManagerStubActivity.java
index 214ced4..d453e3f 100644
--- a/tests/tests/media/src/android/media/cts/ResourceManagerStubActivity.java
+++ b/tests/tests/media/src/android/media/cts/ResourceManagerStubActivity.java
@@ -53,7 +53,7 @@
                     Context context = getApplicationContext();
                     Intent intent1 = new Intent(context, ResourceManagerTestActivity1.class);
                     startActivityForResult(intent1, mRequestCodes[0]);
-                    Thread.sleep(2000);  // wait for process to launch.
+                    Thread.sleep(5000);  // wait for process to launch and allocate all codecs.
 
                     Intent intent2 = new Intent(context, ResourceManagerTestActivity2.class);
                     startActivityForResult(intent2, mRequestCodes[1]);
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java
index 6e395aa..6c416ca 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiEnterpriseConfigTest.java
@@ -32,6 +32,10 @@
     private static final String IDENTITY = "identity";
     private static final String PASSWORD = "password";
     private static final String SUBJECT_MATCH = "subjectmatch";
+    private static final String ALT_SUBJECT_MATCH = "altsubjectmatch";
+    private static final String DOM_SUBJECT_MATCH = "domsubjectmatch";
+    private static final String PLMN = "plmn";
+    private static final String REALM = "realm";
     private static final String ANON_IDENTITY = "anonidentity";
     private static final int ENABLE_DELAY = 10000;
 
@@ -87,6 +91,15 @@
         config.setClientKeyEntry(null, null);
         config.setSubjectMatch(SUBJECT_MATCH);
         assertTrue(config.getSubjectMatch().equals(SUBJECT_MATCH));
+        // Hotspot 2.0 related attributes
+        config.setPlmn(PLMN);
+        assertTrue(config.getPlmn().equals(PLMN));
+        config.setPlmn(REALM);
+        assertTrue(config.getRealm().equals(REALM));
+        config.setAltSubjectMatch(ALT_SUBJECT_MATCH);
+        assertTrue(config.getAltSubjectMatch().equals(ALT_SUBJECT_MATCH));
+        config.setDomainSuffixMatch(DOM_SUBJECT_MATCH);
+        assertTrue(config.getDomainSuffixMatch().equals(DOM_SUBJECT_MATCH));
     }
 
     public void testAddEapNetwork() {
diff --git a/tests/tests/os/jni/Android.mk b/tests/tests/os/jni/Android.mk
index 24a0651..c125f5c 100644
--- a/tests/tests/os/jni/Android.mk
+++ b/tests/tests/os/jni/Android.mk
@@ -38,6 +38,12 @@
 	ARCH_SUPPORTS_SECCOMP = 1
 endif
 
+ifeq ($(strip $(TARGET_ARCH)),arm64)
+	ARCH_SUPPORTS_SECCOMP = 1
+	# Required for __NR_poll definition.
+	LOCAL_CFLAGS += -D__ARCH_WANT_SYSCALL_DEPRECATED
+endif
+
 ifeq ($(strip $(TARGET_ARCH)),x86)
 	ARCH_SUPPORTS_SECCOMP = 1
 endif
diff --git a/tests/tests/os/jni/seccomp_sample_program.cpp b/tests/tests/os/jni/seccomp_sample_program.cpp
index e291e8a..3c90196 100644
--- a/tests/tests/os/jni/seccomp_sample_program.cpp
+++ b/tests/tests/os/jni/seccomp_sample_program.cpp
@@ -355,8 +355,6 @@
   {0x6, 0, 0, 0x30001},
 };
 #elif defined(__aarch64__)
-// Note: aarch64 is not required to support seccomp-bpf yet, but some Nexus
-// devices do support it. For completeness, this test BPF program is provided.
 struct sock_filter kTestSeccompFilter[] = {
   {0x20, 0, 0, 0x4},
   {0x15, 1, 0, 0xc00000b7},
diff --git a/tests/tests/os/src/android/os/cts/SeccompTest.java b/tests/tests/os/src/android/os/cts/SeccompTest.java
index 4c2f78f..0340580 100644
--- a/tests/tests/os/src/android/os/cts/SeccompTest.java
+++ b/tests/tests/os/src/android/os/cts/SeccompTest.java
@@ -51,9 +51,6 @@
     }
 
     public void testSeccomp() {
-        if (CpuFeatures.isArm64Cpu() || CpuFeatures.isArm64CpuIn32BitMode()) {
-            return; // seccomp not yet supported on arm64
-        }
         if (OSFeatures.needsSeccompSupport()) {
             assertTrue("Please enable seccomp support "
                        + "in your kernel (CONFIG_SECCOMP_FILTER=y)",
diff --git a/tests/tests/os/src/android/os/cts/StrictModeTest.java b/tests/tests/os/src/android/os/cts/StrictModeTest.java
index 7ebe817..d63f8bc 100644
--- a/tests/tests/os/src/android/os/cts/StrictModeTest.java
+++ b/tests/tests/os/src/android/os/cts/StrictModeTest.java
@@ -84,7 +84,7 @@
     }
 
     private String readLogSince(long millis) throws Exception {
-        final SimpleDateFormat format = new SimpleDateFormat("MM-DD HH:mm:ss.SSS");
+        final SimpleDateFormat format = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
         final Process proc = new ProcessBuilder("logcat", "-t", format.format(new Date(millis)))
                 .redirectErrorStream(true).start();
 
diff --git a/tests/tests/permission2/src/android/permission2/cts/NoWriteSecureSettingsPermissionTest.java b/tests/tests/permission2/src/android/permission2/cts/NoWriteSecureSettingsPermissionTest.java
index eb476c7..b46c45d 100644
--- a/tests/tests/permission2/src/android/permission2/cts/NoWriteSecureSettingsPermissionTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/NoWriteSecureSettingsPermissionTest.java
@@ -16,6 +16,9 @@
 
 package android.permission2.cts;
 
+import android.Manifest;
+import android.content.ContentValues;
+import android.provider.Settings;
 import android.test.AndroidTestCase;
 
 /**
@@ -30,7 +33,15 @@
      *   {@link android.Manifest.permission#WRITE_SECURE_SETTINGS}
      */
     public void testWriteSecureSettings() {
-        assertWritingContentUriRequiresPermission(android.provider.Settings.Secure.CONTENT_URI,
-                android.Manifest.permission.WRITE_SECURE_SETTINGS);
+        try {
+            ContentValues values = new ContentValues();
+            values.put(Settings.Secure.NAME, Settings.Secure.ACCESSIBILITY_ENABLED);
+            values.put(Settings.Secure.VALUE, Boolean.TRUE);
+            getContext().getContentResolver().insert(Settings.Secure.CONTENT_URI, values);
+            fail("expected SecurityException requiring "
+                    + Manifest.permission.WRITE_SECURE_SETTINGS);
+        } catch (SecurityException expected) {
+           /* do nothing */
+        }
     }
 }
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/BNNMTest.java b/tests/tests/renderscript/src/android/renderscript/cts/BNNMTest.java
index b36175c..1822f6a 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/BNNMTest.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/BNNMTest.java
@@ -338,4 +338,163 @@
         assertTrue(testWithTolerance(c_byte, c_byte_output));
 
     }
+
+    // This test multiplies matrices where the results are expected to fall
+    // slightly outside the 0 to 255 valid output range. This test ensures the
+    // values get clamped to that range, rather than wrapping around.
+    public void testClamping() {
+        // The A matrix is:
+        // |   1 |   4 |
+        // |   2 |   5 |
+        // |   3 |   6 |
+        byte[] a_data = unsignedToSignedByte(new int[] {
+                1, 2, 3,
+                4, 5, 6,
+            });
+        final int a_rows = 3;
+        final int a_cols = 2;
+        final int a_offset = 0;
+        // The B matrix is:
+        // |  -1 |  -2 |  -3 |  -4 |
+        // |  -5 |  -6 |  -7 |  -8 |
+        // |  99 | -40 | -11 | -15 |
+        byte[] b_data = unsignedToSignedByte(new int[] {
+                126, 122, 226,
+                125, 121, 87,
+                124, 120, 116,
+                123, 119, 112,
+            });
+        final int b_cols = 4;
+        final int b_offset = 127;
+        // EightBitGemm implements C = B.transposed() * A,
+        // so we expect to get these results:
+        // 1*-1 + 2*-5 + 3* 99 + 128 = 414 (clamped to 255)
+        // 1*-2 + 2*-6 + 3*-40 + 128 = -6 (clamped to 0)
+        // 1*-3 + 2*-7 + 3*-11 + 128 = 78
+        // 1*-4 + 2*-8 + 3*-15 + 128 = 63
+        // 4*-1 + 5*-5 + 6* 99 + 128 = 693 (clamped to 255)
+        // 4*-2 + 5*-6 + 6*-40 + 128 = -150 (clamped to 0)
+        // 4*-3 + 5*-7 + 6*-11 + 128 = 15
+        // 4*-4 + 5*-8 + 6*-15 + 128 = -18 (clamped to 0)
+        // | 255 | 255 |
+        // |   0 |   0 |
+        // |  78 |  15 |
+        // |  63 |   0 |
+        final int c_offset = 128;
+        final int c_shift = 21;
+        final int c_mult_int = (1 << c_shift);
+        byte[] expected_data = unsignedToSignedByte(new int[] {
+              255, 0, 78, 63,
+              255, 0, 15, 0,
+            });
+
+        final int m = a_cols;
+        final int n = b_cols;
+        final int k = a_rows;
+
+        byte[] c_byte_output = runBNNM(m, n, k, a_data, a_offset, b_data, b_offset,
+                                       c_offset, c_mult_int);
+        assertTrue(testWithTolerance(expected_data, c_byte_output));
+    }
+
+    // This tests the exception handling for a_offset and b_offset.
+    public void testExceptionHandling() {
+        // The A matrix is:
+        // |   1 |   4 |
+        // |   2 |   5 |
+        // |   3 |   6 |
+        byte[] a_data = unsignedToSignedByte(new int[] {
+                1, 2, 3,
+                4, 5, 6,
+            });
+        final int a_rows = 3;
+        final int a_cols = 2;
+        // The B matrix is:
+        // |  -1 |  -2 |  -3 |  -4 |
+        // |  -5 |  -6 |  -7 |  -8 |
+        // |  -9 | -10 | -11 | -12 |
+        byte[] b_data = unsignedToSignedByte(new int[] {
+                11, 7, 3,
+                10, 6, 2,
+                9, 5, 1,
+                8, 4, 0,
+            });
+        final int b_cols = 4;
+        // EightBitGemm implements C = B.transposed() * A,
+        // so we expect to get these results:
+        // 1*-1 + 2*-5 + 3*-9 + 128 = 90
+        // 1*-2 + 2*-6 + 3*-10 + 128 = 84
+        // 1*-3 + 2*-7 + 3*-11 + 128 = 78
+        // 1*-4 + 2*-8 + 3*-12 + 128 = 72
+        // 4*-1 + 5*-5 + 6*-9 + 128 = 45
+        // 4*-2 + 5*-6 + 6*-10 + 128 = 30
+        // 4*-3 + 5*-7 + 6*-11 + 128 = 15
+        // 4*-4 + 5*-8 + 6*-12 + 128 = 0
+        // | 90 |  45 |
+        // | 84 |  30 |
+        // | 78 | 15 |
+        // | 72 | 0 |
+        final int c_offset = 128;
+        final int c_shift = 21;
+        final int c_mult_int = (1 << c_shift);
+        byte[] expected_data = unsignedToSignedByte(new int[] {
+                90, 84, 78, 72,
+                45, 30, 15, 0,
+            });
+
+        final int m = a_cols;
+        final int n = b_cols;
+        final int k = a_rows;
+
+        Allocation A, B, C;
+        Type.Builder builder = new Type.Builder(mRS, Element.U8(mRS));
+        Type a_type = builder.setX(k).setY(m).create();
+        Type b_type = builder.setX(k).setY(n).create();
+        Type c_type = builder.setX(n).setY(m).create();
+
+        A = Allocation.createTyped(mRS, a_type);
+        B = Allocation.createTyped(mRS, b_type);
+        C = Allocation.createTyped(mRS, c_type);
+
+        A.copyFrom(a_data);
+        B.copyFrom(b_data);
+        // C doesn't matter, is output only
+
+        ScriptIntrinsicBLAS blas = ScriptIntrinsicBLAS.create(mRS);
+        try {
+            int a_offset = 0;
+            int b_offset = 12;
+            blas.BNNM(A, a_offset, B, b_offset, C, c_offset, c_mult_int);
+        } catch (RSRuntimeException e) {
+            fail("should NOT throw RSRuntimeException for valid offsets");
+        }
+        try {
+            int a_offset = -23;
+            int b_offset = 12;
+            blas.BNNM(A, a_offset, B, b_offset, C, c_offset, c_mult_int);
+            fail("should throw RSRuntimeException for invalid offsets: a_offset < 0");
+        } catch (RSRuntimeException e) {
+        }
+        try {
+            int a_offset = 888;
+            int b_offset = 12;
+            blas.BNNM(A, a_offset, B, b_offset, C, c_offset, c_mult_int);
+            fail("should throw RSRuntimeException for invalid offsets: a_offset > 255");
+        } catch (RSRuntimeException e) {
+        }
+        try {
+            int a_offset = 0;
+            int b_offset = -1;
+            blas.BNNM(A, a_offset, B, b_offset, C, c_offset, c_mult_int);
+            fail("should throw RSRuntimeException for invalid offsets: b_offset < 0");
+        } catch (RSRuntimeException e) {
+        }
+        try {
+            int a_offset = 0;
+            int b_offset = 256;
+            blas.BNNM(A, a_offset, B, b_offset, C, c_offset, c_mult_int);
+            fail("should throw RSRuntimeException for invalid offsets: b_offset > 255");
+        } catch (RSRuntimeException e) {
+        }
+    }
 }
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/YuvTest.java b/tests/tests/renderscript/src/android/renderscript/cts/YuvTest.java
index 5cdfe95..e162d1d 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/YuvTest.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/YuvTest.java
@@ -97,11 +97,11 @@
         Allocation ta = Allocation.createSized(mRS, Element.U8(mRS), tmp.length);
         ta.copyFrom(tmp);
 
-
         ScriptIntrinsicYuvToRGB syuv = ScriptIntrinsicYuvToRGB.create(mRS, Element.U8(mRS));
         syuv.setInput(ta);
         syuv.forEach(aout);
-
+        
+        mVerify.set_gAllowedIntError(2); // this will allow for less strict implementation
         ScriptC_yuv script = new ScriptC_yuv(mRS);
         script.invoke_makeRef(ay, au, av, aref);
 
@@ -141,7 +141,8 @@
         }
         ta.copyFrom(tmp);
         script.invoke_makeRef(ay, au, av, aref);
-
+        
+        mVerify.set_gAllowedIntError(2); // this will allow for less strict implementation
         syuv.setInput(ta);
         syuv.forEach(aout);
         mVerify.invoke_verify(aref, aout, ay);
@@ -186,6 +187,7 @@
         }
         ta.copyFrom(tmp);
         script.invoke_makeRef(ay, au, av, aref);
+        mVerify.set_gAllowedIntError(2); // this will allow for less strict implementation
 
         syuv.setInput(ta);
         syuv.forEach(aout);
@@ -236,6 +238,7 @@
         mVerify.invoke_verify(aref, aout, ay);
 
         mRS.finish();
+        mVerify.set_gAllowedFloatError(0.01f); // this will allow for less strict implementation
         mVerify.invoke_checkError();
         waitForMessage();
         checkForErrors();
@@ -266,11 +269,13 @@
             tmp[i++] = bv[j];
             tmp[i++] = bu[j];
         }
+
         ta.copyFrom(tmp);
         script.invoke_makeRef_f4(ay, au, av, aref);
 
         script.set_mInput(ta);
         script.forEach_cvt_f4(aout);
+        mVerify.set_gAllowedFloatError(0.01f); // this will allow for less strict implementation
         mVerify.invoke_verify(aref, aout, ay);
 
         mRS.finish();
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/verify.rs b/tests/tests/renderscript/src/android/renderscript/cts/verify.rs
index f6d625b..c3ae802 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/verify.rs
+++ b/tests/tests/renderscript/src/android/renderscript/cts/verify.rs
@@ -17,13 +17,14 @@
 #include "shared.rsh"
 
 int gAllowedIntError = 0;
-double gAllowedFloatError = 0.00000001;
-double gAllowedDoubleError = 0.00000000001;
+float gAllowedFloatError = 0.0001f;
+double gAllowedFloatMatError = 0.00000001;
+double gAllowedDoubleMatError = 0.00000000001;
 static bool hadError = false;
 static int2 errorLoc = {0,0};
 
 static bool compare_float(float f1, float f2) {
-    if (fabs(f1-f2) > 0.0001f) {
+    if (fabs(f1-f2) > gAllowedFloatError) {
         hadError = true;
         return false;
     }
@@ -316,7 +317,7 @@
             float2 pref = rsGetElementAt_float2(in1, x, y);
             float2 ptst = rsGetElementAt_float2(in2, x, y);
             double absErr = (pref.x - ptst.x) * (pref.x - ptst.x) + (pref.y - ptst.y) * (pref.y - ptst.y);
-            if (absErr > l2Norm * gAllowedFloatError) {
+            if (absErr > l2Norm * gAllowedFloatMatError) {
                 errorLoc.x = x;
                 errorLoc.y = y;
                 hadError = true;
@@ -340,7 +341,7 @@
             float pref = rsGetElementAt_float(in1, x, y);
             float ptst = rsGetElementAt_float(in2, x, y);
             double absErr = (pref - ptst) * (pref - ptst);
-            if (absErr > l2Norm * gAllowedFloatError) {
+            if (absErr > l2Norm * gAllowedFloatMatError) {
                 errorLoc.x = x;
                 errorLoc.y = y;
                 hadError = true;
@@ -364,7 +365,7 @@
             double2 pref = rsGetElementAt_double2(in1, x, y);
             double2 ptst = rsGetElementAt_double2(in2, x, y);
             double absErr = (pref.x - ptst.x) * (pref.x - ptst.x) + (pref.y - ptst.y) * (pref.y - ptst.y);
-            if (absErr > l2Norm * gAllowedDoubleError) {
+            if (absErr > l2Norm * gAllowedDoubleMatError) {
                 errorLoc.x = x;
                 errorLoc.y = y;
                 hadError = true;
@@ -388,7 +389,7 @@
             double pref = rsGetElementAt_double(in1, x, y);
             double ptst = rsGetElementAt_double(in2, x, y);
             double absErr = (pref - ptst) * (pref - ptst);
-            if (absErr > l2Norm * gAllowedDoubleError) {
+            if (absErr > l2Norm * gAllowedDoubleMatError) {
                 errorLoc.x = x;
                 errorLoc.y = y;
                 hadError = true;
diff --git a/tests/tests/text/src/android/text/format/cts/FormatterTest.java b/tests/tests/text/src/android/text/format/cts/FormatterTest.java
index bf4a684..9c3c45d 100644
--- a/tests/tests/text/src/android/text/format/cts/FormatterTest.java
+++ b/tests/tests/text/src/android/text/format/cts/FormatterTest.java
@@ -32,24 +32,24 @@
         BigDecimal bd = new BigDecimal((long) 1024, mc);
 
         // test different long values with various length
-        assertEquals("0.00B", Formatter.formatFileSize(mContext, 0));
+        assertEquals("0.00 B", Formatter.formatFileSize(mContext, 0));
 
-        assertEquals("899B", Formatter.formatFileSize(mContext, 899));
+        assertEquals("899 B", Formatter.formatFileSize(mContext, 899));
 
-        assertEquals("1.00KB", Formatter.formatFileSize(mContext, bd.pow(1).longValue()));
+        assertEquals("1.00 KB", Formatter.formatFileSize(mContext, bd.pow(1).longValue()));
 
-        assertEquals("1.00MB", Formatter.formatFileSize(mContext, bd.pow(2).longValue()));
+        assertEquals("1.00 MB", Formatter.formatFileSize(mContext, bd.pow(2).longValue()));
 
-        assertEquals("1.00GB", Formatter.formatFileSize(mContext, bd.pow(3).longValue()));
+        assertEquals("1.00 GB", Formatter.formatFileSize(mContext, bd.pow(3).longValue()));
 
-        assertEquals("1.00TB", Formatter.formatFileSize(mContext, bd.pow(4).longValue()));
+        assertEquals("1.00 TB", Formatter.formatFileSize(mContext, bd.pow(4).longValue()));
 
-        assertEquals("1.00PB", Formatter.formatFileSize(mContext, bd.pow(5).longValue()));
+        assertEquals("1.00 PB", Formatter.formatFileSize(mContext, bd.pow(5).longValue()));
 
-        assertEquals("1024PB", Formatter.formatFileSize(mContext, bd.pow(6).longValue()));
+        assertEquals("1024 PB", Formatter.formatFileSize(mContext, bd.pow(6).longValue()));
 
         // test Negative value
-        assertEquals("-1.00B", Formatter.formatFileSize(mContext, -1));
+        assertEquals("-1.00 B", Formatter.formatFileSize(mContext, -1));
     }
 
     public void testFormatIpAddress() {
diff --git a/tests/tests/view/src/android/view/cts/ActionModeTest.java b/tests/tests/view/src/android/view/cts/ActionModeTest.java
index 6898d3c..534db311 100644
--- a/tests/tests/view/src/android/view/cts/ActionModeTest.java
+++ b/tests/tests/view/src/android/view/cts/ActionModeTest.java
@@ -67,6 +67,57 @@
         assertTrue(callback.mIsOnGetContentRectCalled);
     }
 
+    public void testSetAndGetTitleOptionalHint() {
+        MockActionMode actionMode = new MockActionMode();
+
+        // Check default value.
+        assertFalse(actionMode.getTitleOptionalHint());
+        // Test set and get.
+        actionMode.setTitleOptionalHint(true);
+        assertTrue(actionMode.getTitleOptionalHint());
+        actionMode.setTitleOptionalHint(false);
+        assertFalse(actionMode.getTitleOptionalHint());
+    }
+
+    public void testSetAndGetTag() {
+        MockActionMode actionMode = new MockActionMode();
+        Object tag = new Object();
+
+        // Check default value.
+        assertNull(actionMode.getTag());
+
+        actionMode.setTag(tag);
+        assertSame(tag, actionMode.getTag());
+    }
+
+    public void testIsTitleOptional() {
+        MockActionMode actionMode = new MockActionMode();
+
+        // Check default value.
+        assertFalse(actionMode.isTitleOptional());
+    }
+
+    public void testIsUiFocusable() {
+        MockActionMode actionMode = new MockActionMode();
+
+        // Check default value.
+        assertTrue(actionMode.isUiFocusable());
+    }
+
+    public void testHide() {
+        MockActionMode actionMode = new MockActionMode();
+
+        actionMode.hide(0);
+        actionMode.hide(ActionMode.DEFAULT_HIDE_DURATION);
+    }
+
+    public void testOnWindowFocusChanged() {
+        MockActionMode actionMode = new MockActionMode();
+
+        actionMode.onWindowFocusChanged(true);
+        actionMode.onWindowFocusChanged(false);
+    }
+
     private static class MockActionModeCallback2 extends ActionMode.Callback2 {
         boolean mIsOnGetContentRectCalled = false;
 
diff --git a/tests/tests/view/src/android/view/cts/MockTextView.java b/tests/tests/view/src/android/view/cts/MockTextView.java
index dc9420d..0c73614 100644
--- a/tests/tests/view/src/android/view/cts/MockTextView.java
+++ b/tests/tests/view/src/android/view/cts/MockTextView.java
@@ -179,19 +179,19 @@
     }
 
     public int getFrameLeft() {
-        return mLeft;
+        return getLeft();
     }
 
     public int getFrameTop() {
-        return mTop;
+        return getTop();
     }
 
     public int getFrameRight() {
-        return mRight;
+        return getRight();
     }
 
     public int getFrameBottom() {
-        return mBottom;
+        return getBottom();
     }
 
     public int getBottomPaddingOffset() {
diff --git a/tests/tests/view/src/android/view/cts/MockView.java b/tests/tests/view/src/android/view/cts/MockView.java
index 9093089..579d4fb 100644
--- a/tests/tests/view/src/android/view/cts/MockView.java
+++ b/tests/tests/view/src/android/view/cts/MockView.java
@@ -29,6 +29,7 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.view.ContextMenu.ContextMenuInfo;
 
@@ -104,8 +105,8 @@
         return mCalledInvalidate;
     }
 
-    public void setParent(ViewParent parent) {
-        mParent = parent;
+    public void setParent(ViewGroup parent) {
+        parent.addView(this);
     }
 
     public static int[] getEnabledStateSet() {
@@ -162,16 +163,6 @@
     }
 
     @Override
-    protected void initializeFadingEdge(TypedArray a) {
-        super.initializeFadingEdge(a);
-    }
-
-    @Override
-    protected void initializeScrollbars(TypedArray a) {
-        super.initializeScrollbars(a);
-    }
-
-    @Override
     protected int getHorizontalScrollbarHeight() {
         return super.getHorizontalScrollbarHeight();
     }
diff --git a/tests/tests/view/src/android/view/cts/ViewConfigurationTest.java b/tests/tests/view/src/android/view/cts/ViewConfigurationTest.java
index 38e9130..5fe4aea 100644
--- a/tests/tests/view/src/android/view/cts/ViewConfigurationTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewConfigurationTest.java
@@ -42,11 +42,17 @@
         ViewConfiguration.getTouchSlop();
         ViewConfiguration.getWindowTouchSlop();
         ViewConfiguration.getMinimumFlingVelocity();
+        ViewConfiguration.getMaximumFlingVelocity();
         ViewConfiguration.getMaximumDrawingCacheSize();
         ViewConfiguration.getZoomControlsTimeout();
         ViewConfiguration.getGlobalActionKeyTimeout();
         ViewConfiguration.getScrollFriction();
+        ViewConfiguration.getScrollBarFadeDuration();
+        ViewConfiguration.getScrollDefaultDelay();
         ViewConfiguration.getDoubleTapTimeout();
+        ViewConfiguration.getKeyRepeatTimeout();
+        ViewConfiguration.getKeyRepeatDelay();
+        ViewConfiguration.getDefaultActionModeHideDuration();
     }
 
     @SuppressWarnings("deprecation")
@@ -61,9 +67,14 @@
         vc.getScaledEdgeSlop();
         vc.getScaledFadingEdgeLength();
         vc.getScaledMaximumDrawingCacheSize();
+        vc.getScaledMaximumFlingVelocity();
         vc.getScaledMinimumFlingVelocity();
+        vc.getScaledOverflingDistance();
+        vc.getScaledOverscrollDistance();
+        vc.getScaledPagingTouchSlop();
         vc.getScaledScrollBarSize();
         vc.getScaledTouchSlop();
         vc.getScaledWindowTouchSlop();
+        vc.hasPermanentMenuKey();
     }
 }
diff --git a/tests/tests/view/src/android/view/cts/ViewGroupTest.java b/tests/tests/view/src/android/view/cts/ViewGroupTest.java
index b98ac4e..7fc5579 100644
--- a/tests/tests/view/src/android/view/cts/ViewGroupTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewGroupTest.java
@@ -458,7 +458,7 @@
         MockTextView textView = new MockTextView(mContext);
         vg.addView(textView);
         vg.requestChildFocus(textView, null);
-        textView.setFrame(1, 1, 100, 100);
+        textView.layout(1, 1, 100, 100);
 
         assertTrue(vg.dispatchKeyEvent(event));
     }
@@ -529,7 +529,7 @@
         d.getMetrics(metrics);
         int screenWidth = metrics.widthPixels;
         int screenHeight = metrics.heightPixels;
-        vg.setFrame(0, 0, screenWidth, screenHeight);
+        vg.layout(0, 0, screenWidth, screenHeight);
         vg.setLayoutParams(new ViewGroup.LayoutParams(screenWidth, screenHeight));
 
         MockTextView textView = new MockTextView(mContext);
@@ -554,7 +554,7 @@
         assertFalse(vg.dispatchTouchEvent(me));
         assertNull(mMotionEvent);
 
-        textView.setFrame(0, 0, screenWidth, screenHeight);
+        textView.layout(0, 0, screenWidth, screenHeight);
         assertTrue(vg.dispatchTouchEvent(me));
         assertSame(me, mMotionEvent);
     }
@@ -568,7 +568,7 @@
 
         MockTextView textView = new MockTextView(mContext);
         vg.addView(textView);
-        textView.setFrame(1, 1, 100, 100);
+        textView.layout(1, 1, 100, 100);
         vg.requestChildFocus(textView, null);
         assertTrue(vg.dispatchTrackballEvent(me));
     }
@@ -579,7 +579,7 @@
         assertFalse(vg.dispatchUnhandledMove(textView, View.FOCUS_DOWN));
 
         vg.addView(textView);
-        textView.setFrame(1, 1, 100, 100);
+        textView.layout(1, 1, 100, 100);
         vg.requestChildFocus(textView, null);
         assertTrue(vg.dispatchUnhandledMove(textView, View.FOCUS_DOWN));
     }
@@ -769,13 +769,13 @@
         MockViewGroup vg = new MockViewGroup(mContext);
         MockTextView textView = new MockTextView(mContext);
 
-        textView.setFrame(1, 1, 100, 100);
+        textView.layout(1, 1, 100, 100);
         Rect rect = new Rect(1, 1, 50, 50);
         Point p = new Point();
         assertFalse(vg.getChildVisibleRect(textView, rect, p));
 
-        textView.setFrame(0, 0, 0, 0);
-        vg.setFrame(20, 20, 60, 60);
+        textView.layout(0, 0, 0, 0);
+        vg.layout(20, 20, 60, 60);
         rect = new Rect(10, 10, 40, 40);
         p = new Point();
         assertTrue(vg.getChildVisibleRect(textView, rect, p));
@@ -998,7 +998,7 @@
             // expected
         }
         vg.addView(textView);
-        textView.setFrame(1, 2, 3, 4);
+        textView.layout(1, 2, 3, 4);
         Rect rect = new Rect();
         vg.offsetDescendantRectToMyCoords(textView, rect);
         assertEquals(2, rect.bottom);
@@ -1009,7 +1009,7 @@
 
     public void testOffsetRectIntoDescendantCoords() {
         MockViewGroup vg = new MockViewGroup(mContext);
-        vg.setFrame(10, 20, 30, 40);
+        vg.layout(10, 20, 30, 40);
         MockTextView textView = new MockTextView(mContext);
 
         try {
@@ -1019,7 +1019,7 @@
         } catch (RuntimeException e) {
             // expected
         }
-        textView.setFrame(1, 2, 3, 4);
+        textView.layout(1, 2, 3, 4);
         vg.addView(textView);
 
         Rect rect = new Rect(5, 6, 7, 8);
@@ -1376,8 +1376,8 @@
 
         MockViewGroup vg = new MockViewGroup(mContext);
         MockTextView textView = new MockTextView(mContext);
-        textView.setFrame(1, 2, 30, 40);
-        vg.setFrame(1, 1, 100, 200);
+        textView.layout(1, 2, 30, 40);
+        vg.layout(1, 1, 100, 200);
         vg.setClipChildren(true);
 
         MockCanvas canvas = new MockCanvas(bitmap);
@@ -1434,7 +1434,7 @@
         final int frameRight = 100;
         final int frameBottom = 200;
         MockViewGroup vg = new MockViewGroup(mContext);
-        vg.setFrame(frameLeft, frameTop, frameRight, frameBottom);
+        vg.layout(frameLeft, frameTop, frameRight, frameBottom);
 
         vg.setClipToPadding(true);
         MockCanvas canvas = new MockCanvas();
@@ -1911,11 +1911,6 @@
         }
 
         @Override
-        public boolean setFrame(int l, int t, int r, int b) {
-            return super.setFrame(l, t, r, b);
-        }
-
-        @Override
         public void dispatchRestoreInstanceState(
                 SparseArray<Parcelable> container) {
             isDispatchRestoreInstanceStateCalled = true;
@@ -1945,11 +1940,6 @@
         }
 
         @Override
-        public boolean gatherTransparentRegion(Region region) {
-            return false;
-        }
-
-        @Override
         public boolean dispatchTouchEvent(MotionEvent event) {
             super.dispatchTouchEvent(event);
             return true;
@@ -2162,21 +2152,6 @@
         }
 
         @Override
-        public boolean setFrame(int left, int top, int right, int bottom) {
-            return super.setFrame(left, top, right, bottom);
-        }
-
-        @Override
-        public boolean isChildrenDrawnWithCacheEnabled() {
-            return super.isChildrenDrawnWithCacheEnabled();
-        }
-
-        @Override
-        public void setChildrenDrawnWithCacheEnabled(boolean enabled) {
-            super.setChildrenDrawnWithCacheEnabled(enabled);
-        }
-
-        @Override
         public void measureChild(View child, int parentWidthMeasureSpec,
                 int parentHeightMeasureSpec) {
             measureChildCalledTime++;
@@ -2327,6 +2302,21 @@
             super.resetResolvedDrawables();
             resetResolvedDrawablesCount++;
         }
+
+        @Override
+        public boolean setFrame(int left, int top, int right, int bottom) {
+            return super.setFrame(left, top, right, bottom);
+        }
+
+        @Override
+        public void setChildrenDrawnWithCacheEnabled(boolean enabled) {
+            super.setChildrenDrawnWithCacheEnabled(enabled);
+        }
+
+        @Override
+        public boolean isChildrenDrawnWithCacheEnabled() {
+            return super.isChildrenDrawnWithCacheEnabled();
+        }
     }
 
     static class MockView2 extends View {
diff --git a/tests/tests/view/src/android/view/cts/ViewGroup_MarginLayoutParamsTest.java b/tests/tests/view/src/android/view/cts/ViewGroup_MarginLayoutParamsTest.java
index e837b23..e53cba2 100644
--- a/tests/tests/view/src/android/view/cts/ViewGroup_MarginLayoutParamsTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewGroup_MarginLayoutParamsTest.java
@@ -89,7 +89,9 @@
     public void testSetMarginsRelative() {
         // create a new MarginLayoutParams instance
         mMarginLayoutParams = new ViewGroup.MarginLayoutParams(320, 480);
-        mMarginLayoutParams.setMarginsRelative(20, 30, 120, 140);
+        mMarginLayoutParams.setMargins(0, 30, 0, 140);
+        mMarginLayoutParams.setMarginStart(20);
+        mMarginLayoutParams.setMarginEnd(120);
         assertEquals(20, mMarginLayoutParams.getMarginStart());
         assertEquals(30, mMarginLayoutParams.topMargin);
         assertEquals(120, mMarginLayoutParams.getMarginEnd());
@@ -120,7 +122,9 @@
         assertEquals(false, mMarginLayoutParams.isMarginRelative());
 
         // LTR / relative margin case
-        mMarginLayoutParams.setMarginsRelative(20, 30, 120, 140);
+        mMarginLayoutParams.setMargins(0, 30, 0, 140);
+        mMarginLayoutParams.setMarginStart(20);
+        mMarginLayoutParams.setMarginEnd(120);
         vg.setLayoutParams(mMarginLayoutParams);
 
         assertEquals(20, mMarginLayoutParams.getMarginStart());
@@ -151,7 +155,9 @@
         assertEquals(false, mMarginLayoutParams.isMarginRelative());
 
         // RTL / relative margin case
-        mMarginLayoutParams.setMarginsRelative(20, 30, 120, 140);
+        mMarginLayoutParams.setMargins(0, 30, 0, 140);
+        mMarginLayoutParams.setMarginStart(20);
+        mMarginLayoutParams.setMarginEnd(120);
         vg.setLayoutParams(mMarginLayoutParams);
 
         assertEquals(20, mMarginLayoutParams.getMarginStart());
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index ea289ce..e95236d 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -16,28 +16,26 @@
 
 package android.view.cts;
 
-import android.content.res.ColorStateList;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.PorterDuff;
-
-import android.os.Bundle;
 import com.android.cts.view.R;
 import com.android.internal.view.menu.ContextMenuBuilder;
-import com.google.android.collect.Lists;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.cts.util.PollingCheck;
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
 import android.graphics.Point;
+import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.StateListDrawable;
+import android.os.Bundle;
 import android.os.Parcelable;
 import android.os.SystemClock;
 import android.os.Vibrator;
@@ -64,6 +62,7 @@
 import android.view.View;
 import android.view.View.BaseSavedState;
 import android.view.View.OnClickListener;
+import android.view.View.OnContextClickListener;
 import android.view.View.OnCreateContextMenuListener;
 import android.view.View.OnFocusChangeListener;
 import android.view.View.OnKeyListener;
@@ -425,7 +424,9 @@
         assertTrue(view.isLayoutRequested());
 
         view.setParent(mMockParent);
-        assertFalse(mMockParent.hasRequestLayout());
+        assertTrue(mMockParent.hasRequestLayout());
+
+        mMockParent.reset();
         view.requestLayout();
         assertTrue(view.isLayoutRequested());
         assertTrue(mMockParent.hasRequestLayout());
@@ -883,6 +884,18 @@
         assertFalse(view.isClickable());
     }
 
+    public void testAccessContextClickable() {
+        View view = new View(mActivity);
+
+        assertFalse(view.isContextClickable());
+
+        view.setContextClickable(true);
+        assertTrue(view.isContextClickable());
+
+        view.setContextClickable(false);
+        assertFalse(view.isContextClickable());
+    }
+
     public void testGetContextMenuInfo() {
         MockView view = new MockView(mActivity);
 
@@ -1131,8 +1144,8 @@
         mockView2.setParent(mMockParent);
 
         mMockParent.dispatchSetSelected(true);
-        assertFalse(mockView1.isSelected());
-        assertFalse(mockView2.isSelected());
+        assertTrue(mockView1.isSelected());
+        assertTrue(mockView2.isSelected());
 
         mMockParent.dispatchSetSelected(false);
         assertFalse(mockView1.isSelected());
@@ -1155,8 +1168,8 @@
         mockView2.setParent(mMockParent);
 
         mMockParent.dispatchSetPressed(true);
-        assertFalse(mockView1.isPressed());
-        assertFalse(mockView2.isPressed());
+        assertTrue(mockView1.isPressed());
+        assertTrue(mockView2.isPressed());
 
         mMockParent.dispatchSetPressed(false);
         assertFalse(mockView1.isPressed());
@@ -1317,6 +1330,30 @@
         assertTrue(view.isLongClickable());
     }
 
+    public void testPerformContextClick() {
+        MockView view = new MockView(mActivity);
+        view.setParent(mMockParent);
+        OnContextClickListenerImpl listener = new OnContextClickListenerImpl();
+
+        view.setOnContextClickListener(listener);
+        assertFalse(listener.hasOnContextClick());
+
+        assertTrue(view.performContextClick());
+        assertTrue(listener.hasOnContextClick());
+    }
+
+    public void testSetOnContextClickListener() {
+        MockView view = new MockView(mActivity);
+        view.setParent(mMockParent);
+
+        assertFalse(view.performContextClick());
+        assertFalse(view.isContextClickable());
+
+        view.setOnContextClickListener(new OnContextClickListenerImpl());
+        assertTrue(view.performContextClick());
+        assertTrue(view.isContextClickable());
+    }
+
     public void testAccessOnFocusChangeListener() {
         View view = new View(mActivity);
         OnFocusChangeListener listener = new OnFocusChangeListenerImpl();
@@ -3017,16 +3054,13 @@
 
     @UiThreadTest
     public void testScrollbarStyle() {
-        MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
+        MockView view = (MockView) mActivity.findViewById(R.id.scroll_view);
         Bitmap bitmap = Bitmap.createBitmap(200, 300, Bitmap.Config.RGB_565);
         BitmapDrawable d = new BitmapDrawable(bitmap);
         view.setBackgroundDrawable(d);
         view.setHorizontalFadingEdgeEnabled(true);
         view.setVerticalFadingEdgeEnabled(true);
 
-        view.setHorizontalScrollBarEnabled(true);
-        view.setVerticalScrollBarEnabled(true);
-        view.initializeScrollbars(mActivity.obtainStyledAttributes(android.R.styleable.View));
         assertTrue(view.isHorizontalScrollBarEnabled());
         assertTrue(view.isVerticalScrollBarEnabled());
         int verticalScrollBarWidth = view.getVerticalScrollbarWidth();
@@ -3156,7 +3190,10 @@
 
     public void testOnStartAndFinishTemporaryDetach() throws Throwable {
         final MockListView listView = new MockListView(mActivity);
-        List<String> items = Lists.newArrayList("1", "2", "3");
+        List<String> items = new ArrayList<>();
+        items.add("1");
+        items.add("2");
+        items.add("3");
         final Adapter<String> adapter = new Adapter<String>(mActivity, 0, items);
 
         runTestOnUiThread(new Runnable() {
@@ -3638,7 +3675,7 @@
         }
     }
 
-    private final static class MockViewParent extends View implements ViewParent {
+    private final static class MockViewParent extends ViewGroup {
         private boolean mHasClearChildFocus = false;
         private boolean mHasRequestLayout = false;
         private boolean mHasCreateContextMenu = false;
@@ -3678,12 +3715,12 @@
         }
 
         @Override
-        protected void dispatchSetPressed(boolean pressed) {
+        public void dispatchSetPressed(boolean pressed) {
             super.dispatchSetPressed(pressed);
         }
 
         @Override
-        protected void dispatchSetSelected(boolean selected) {
+        public void dispatchSetSelected(boolean selected) {
             super.dispatchSetSelected(selected);
         }
 
@@ -3716,23 +3753,15 @@
             return false;
         }
 
+        @Override
+        protected void onLayout(boolean changed, int l, int t, int r, int b) {
+
+        }
+
         public boolean hasGetChildVisibleRect() {
             return mHasGetChildVisibleRect;
         }
 
-        public void invalidateChild(View child, Rect r) {
-            mTempRect = new Rect(r);
-            mHasInvalidateChild = true;
-        }
-
-        public Rect getTempRect() {
-            return mTempRect;
-        }
-
-        public boolean hasInvalidateChild() {
-            return mHasInvalidateChild;
-        }
-
         public ViewParent invalidateChildInParent(int[] location, Rect r) {
             return null;
         }
@@ -3753,6 +3782,7 @@
 
         }
 
+        @Override
         public void requestLayout() {
             mHasRequestLayout = true;
         }
@@ -3955,6 +3985,23 @@
         }
     }
 
+    private static final class OnContextClickListenerImpl implements OnContextClickListener {
+        private boolean mHasContextClick = false;
+
+        public boolean hasOnContextClick() {
+            return mHasContextClick;
+        }
+
+        public void reset() {
+            mHasContextClick = false;
+        }
+
+        public boolean onContextClick(View v) {
+            mHasContextClick = true;
+            return true;
+        }
+    }
+
     private static final class OnFocusChangeListenerImpl implements OnFocusChangeListener {
         private boolean mHasOnFocusChange = false;
 
diff --git a/tests/tests/view/src/android/view/cts/ViewTreeObserverTest.java b/tests/tests/view/src/android/view/cts/ViewTreeObserverTest.java
index 1b21dac..7071808 100644
--- a/tests/tests/view/src/android/view/cts/ViewTreeObserverTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTreeObserverTest.java
@@ -25,8 +25,6 @@
 import android.test.TouchUtils;
 import android.view.View;
 import android.view.ViewTreeObserver;
-import android.view.ViewTreeObserver.InternalInsetsInfo;
-import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
 import android.view.ViewTreeObserver.OnGlobalFocusChangeListener;
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 import android.view.ViewTreeObserver.OnPreDrawListener;
@@ -155,22 +153,6 @@
         }.run();
     }
 
-    public void testAddOnComputeInternalInsetsListener() {
-        final View view1 = mActivity.findViewById(R.id.view1);
-        mViewTreeObserver = view1.getViewTreeObserver();
-
-        MockOnComputeInternalInsetsListener listener = new MockOnComputeInternalInsetsListener();
-        mViewTreeObserver.addOnComputeInternalInsetsListener(listener);
-    }
-
-    public void testRemoveOnComputeInternalInsetsListener() {
-        final View view1 = mActivity.findViewById(R.id.view1);
-        mViewTreeObserver = view1.getViewTreeObserver();
-
-        MockOnComputeInternalInsetsListener listener = new MockOnComputeInternalInsetsListener();
-        mViewTreeObserver.removeOnComputeInternalInsetsListener(listener);
-    }
-
     public void testDispatchOnGlobalLayout() {
         final LinearLayout layout = (LinearLayout) mActivity.findViewById(R.id.linearlayout);
         mViewTreeObserver = layout.getViewTreeObserver();
@@ -434,12 +416,6 @@
         }
     }
 
-    private class MockOnComputeInternalInsetsListener implements OnComputeInternalInsetsListener {
-        @Override
-        public void onComputeInternalInsets(InternalInsetsInfo inoutInfo) {
-        }
-    }
-
     private static class MockOnScrollChangedListener implements OnScrollChangedListener {
         private boolean mCalledOnScrollChanged = false;
 
diff --git a/tests/tests/view/src/android/view/cts/util/XmlUtils.java b/tests/tests/view/src/android/view/cts/util/XmlUtils.java
index 4a13d54..f1df4ff 100644
--- a/tests/tests/view/src/android/view/cts/util/XmlUtils.java
+++ b/tests/tests/view/src/android/view/cts/util/XmlUtils.java
@@ -16,8 +16,6 @@
 
 package android.view.cts.util;
 
-import com.android.internal.util.FastXmlSerializer;
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -44,7 +42,6 @@
 import java.util.Map;
 import java.util.Set;
 
-/** {@hide} */
 public class XmlUtils {
 
     public static void skipCurrentTag(XmlPullParser parser)
@@ -171,28 +168,6 @@
     }
 
     /**
-     * Flatten a Map into an output stream as XML.  The map can later be
-     * read back with readMapXml().
-     *
-     * @param val The map to be flattened.
-     * @param out Where to write the XML data.
-     *
-     * @see #writeMapXml(Map, String, XmlSerializer)
-     * @see #writeListXml
-     * @see #writeValueXml
-     * @see #readMapXml
-     */
-    public static final void writeMapXml(Map val, OutputStream out)
-            throws XmlPullParserException, IOException {
-        XmlSerializer serializer = new FastXmlSerializer();
-        serializer.setOutput(out, StandardCharsets.UTF_8.name());
-        serializer.startDocument(null, true);
-        serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-        writeMapXml(val, null, serializer);
-        serializer.endDocument();
-    }
-
-    /**
      * Flatten a List into an output stream as XML.  The list can later be
      * read back with readListXml().
      *
@@ -224,7 +199,6 @@
      *             none.
      * @param out XmlSerializer to write the map into.
      *
-     * @see #writeMapXml(Map, OutputStream)
      * @see #writeListXml
      * @see #writeValueXml
      * @see #readMapXml
@@ -244,7 +218,6 @@
      * @param out XmlSerializer to write the map into.
      * @param callback Method to call when an Object type is not recognized.
      *
-     * @see #writeMapXml(Map, OutputStream)
      * @see #writeListXml
      * @see #writeValueXml
      * @see #readMapXml
@@ -278,7 +251,6 @@
      * @param val The map to be flattened.
      * @param out XmlSerializer to write the map into.
      *
-     * @see #writeMapXml(Map, OutputStream)
      * @see #writeListXml
      * @see #writeValueXml
      * @see #readMapXml
diff --git a/tests/tests/widget/src/android/widget/cts/CursorAdapterTest.java b/tests/tests/widget/src/android/widget/cts/CursorAdapterTest.java
index 7fe016f..fc5eb08 100644
--- a/tests/tests/widget/src/android/widget/cts/CursorAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CursorAdapterTest.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.content.res.Resources.Theme;
 import android.cts.util.PollingCheck;
-import android.cts.util.ReadElf;
 import android.cts.util.TestThread;
 import android.database.ContentObserver;
 import android.database.Cursor;
@@ -40,7 +39,6 @@
 
 import com.android.cts.widget.R;
 
-
 /**
  * Test {@link CursorAdapter}.
  */
@@ -347,14 +345,23 @@
     }
 
     private final class MockCursorAdapter extends CursorAdapter {
+        private final Context mContext;
+        private final boolean mAutoRequery;
+
         private boolean mContentChanged = false;
 
         public MockCursorAdapter(Context context, Cursor c) {
             super(context, c);
+
+            mContext = context;
+            mAutoRequery = false;
         }
 
         public MockCursorAdapter(Context context, Cursor c, boolean autoRequery) {
             super(context, c, autoRequery);
+
+            mContext = context;
+            mAutoRequery = autoRequery;
         }
 
         public Context getContext() {
diff --git a/tests/tests/widget/src/android/widget/cts/GalleryTest.java b/tests/tests/widget/src/android/widget/cts/GalleryTest.java
index 2813965..a3ac16c 100644
--- a/tests/tests/widget/src/android/widget/cts/GalleryTest.java
+++ b/tests/tests/widget/src/android/widget/cts/GalleryTest.java
@@ -17,16 +17,17 @@
 package android.widget.cts;
 
 import com.android.cts.widget.R;
-import com.android.internal.view.menu.ContextMenuBuilder;
-
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.app.Activity;
 import android.app.Instrumentation;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.cts.util.WidgetTestUtils;
+import android.graphics.drawable.Drawable;
 import android.os.SystemClock;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
@@ -36,7 +37,8 @@
 import android.view.ContextMenu;
 import android.view.Gravity;
 import android.view.KeyEvent;
-import android.view.MotionEvent;
+import android.view.MenuItem;
+import android.view.SubMenu;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ContextMenu.ContextMenuInfo;
@@ -311,11 +313,165 @@
         MyGallery gallery = new MyGallery(mContext);
         gallery.setOnCreateContextMenuListener(listener);
         assertFalse(listener.hasCreatedContextMenu());
-        gallery.createContextMenu(new ContextMenuBuilder(mContext));
+        gallery.createContextMenu(new MockContextMenu());
         assertTrue(listener.hasCreatedContextMenu());
         assertSame(gallery.getContextMenuInfo(), listener.getContextMenuInfo());
     }
 
+    private static class MockContextMenu implements ContextMenu {
+        @Override
+        public ContextMenu setHeaderTitle(int titleRes) {
+            return null;
+        }
+
+        @Override
+        public ContextMenu setHeaderTitle(CharSequence title) {
+            return null;
+        }
+
+        @Override
+        public ContextMenu setHeaderIcon(int iconRes) {
+            return null;
+        }
+
+        @Override
+        public ContextMenu setHeaderIcon(Drawable icon) {
+            return null;
+        }
+
+        @Override
+        public ContextMenu setHeaderView(View view) {
+            return null;
+        }
+
+        @Override
+        public void clearHeader() {
+
+        }
+
+        @Override
+        public MenuItem add(CharSequence title) {
+            return null;
+        }
+
+        @Override
+        public MenuItem add(int titleRes) {
+            return null;
+        }
+
+        @Override
+        public MenuItem add(int groupId, int itemId, int order, CharSequence title) {
+            return null;
+        }
+
+        @Override
+        public MenuItem add(int groupId, int itemId, int order, int titleRes) {
+            return null;
+        }
+
+        @Override
+        public SubMenu addSubMenu(CharSequence title) {
+            return null;
+        }
+
+        @Override
+        public SubMenu addSubMenu(int titleRes) {
+            return null;
+        }
+
+        @Override
+        public SubMenu addSubMenu(int groupId, int itemId, int order,
+                CharSequence title) {
+            return null;
+        }
+
+        @Override
+        public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) {
+            return null;
+        }
+
+        @Override
+        public int addIntentOptions(int groupId, int itemId, int order, ComponentName caller,
+                Intent[] specifics, Intent intent, int flags, MenuItem[] outSpecificItems) {
+            return 0;
+        }
+
+        @Override
+        public void removeItem(int id) {
+
+        }
+
+        @Override
+        public void removeGroup(int groupId) {
+
+        }
+
+        @Override
+        public void clear() {
+
+        }
+
+        @Override
+        public void setGroupCheckable(int group, boolean checkable, boolean exclusive) {
+
+        }
+
+        @Override
+        public void setGroupVisible(int group, boolean visible) {
+
+        }
+
+        @Override
+        public void setGroupEnabled(int group, boolean enabled) {
+
+        }
+
+        @Override
+        public boolean hasVisibleItems() {
+            return false;
+        }
+
+        @Override
+        public MenuItem findItem(int id) {
+            return null;
+        }
+
+        @Override
+        public int size() {
+            return 0;
+        }
+
+        @Override
+        public MenuItem getItem(int index) {
+            return null;
+        }
+
+        @Override
+        public void close() {
+
+        }
+
+        @Override
+        public boolean performShortcut(int keyCode, KeyEvent event, int flags) {
+            return false;
+        }
+
+        @Override
+        public boolean isShortcutKey(int keyCode, KeyEvent event) {
+            return false;
+        }
+
+        @Override
+        public boolean performIdentifierAction(int id, int flags) {
+            return false;
+        }
+
+        @Override
+        public void setQwertyMode(boolean isQwerty) {
+
+        }
+    }
+
     private static class MockOnCreateContextMenuListener implements OnCreateContextMenuListener {
         private boolean hasCreatedContextMenu;
         private ContextMenuInfo mContextMenuInfo;
diff --git a/tests/tests/widget/src/android/widget/cts/ImageViewTest.java b/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
index c93d4a1..aa1df34 100644
--- a/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
@@ -38,6 +38,7 @@
 import android.graphics.PorterDuff;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
 import android.graphics.drawable.PaintDrawable;
 import android.net.Uri;
 import android.test.ActivityInstrumentationTestCase;
@@ -173,6 +174,23 @@
     }
 
     @UiThreadTest
+    public void testSetImageIcon() {
+        mImageView = findImageViewById(R.id.imageview);
+        mImageView.setImageIcon(null);
+        assertNull(mImageView.getDrawable());
+
+        Icon icon = Icon.createWithResource(mActivity, R.drawable.testimage);
+        mImageView.setImageIcon(icon);
+        assertTrue(mImageView.isLayoutRequested());
+        assertNotNull(mImageView.getDrawable());
+        Drawable drawable = mActivity.getDrawable(R.drawable.testimage);
+        BitmapDrawable testimageBitmap = (BitmapDrawable) drawable;
+        Drawable imageViewDrawable = mImageView.getDrawable();
+        BitmapDrawable imageViewBitmap = (BitmapDrawable) imageViewDrawable;
+        WidgetTestUtils.assertEquals(testimageBitmap.getBitmap(), imageViewBitmap.getBitmap());
+    }
+
+    @UiThreadTest
     public void testSetImageResource() {
         mImageView = findImageViewById(R.id.imageview);
         mImageView.setImageResource(-1);
@@ -181,7 +199,7 @@
         mImageView.setImageResource(R.drawable.testimage);
         assertTrue(mImageView.isLayoutRequested());
         assertNotNull(mImageView.getDrawable());
-        Drawable drawable = mActivity.getResources().getDrawable(R.drawable.testimage);
+        Drawable drawable = mActivity.getDrawable(R.drawable.testimage);
         BitmapDrawable testimageBitmap = (BitmapDrawable) drawable;
         Drawable imageViewDrawable = mImageView.getDrawable();
         BitmapDrawable imageViewBitmap = (BitmapDrawable) imageViewDrawable;
diff --git a/tests/tests/widget/src/android/widget/cts/MyGallery.java b/tests/tests/widget/src/android/widget/cts/MyGallery.java
index 91665ee..27b5d45 100644
--- a/tests/tests/widget/src/android/widget/cts/MyGallery.java
+++ b/tests/tests/widget/src/android/widget/cts/MyGallery.java
@@ -49,10 +49,6 @@
         return super.getChildStaticTransformation(child, t);
     }
 
-    protected void setParent(ViewParent v) {
-        mParent = v;
-    }
-
     @Override
     protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
         return super.checkLayoutParams(p);
diff --git a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
index 24596a4..bb638e4 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
@@ -390,7 +390,11 @@
         assertTrue(maxAvailableHeightWithOffset <= avaliable);
 
         anchorView = mActivity.findViewById(R.id.anchor_lower);
-        avaliable = getDisplay().getHeight() - anchorView.getHeight();
+        // On some devices the view might actually have larger size than the physical display
+        // due to chin and content will be laid out as if outside of the display. We need to use
+        // larger from the display height and the main view height.
+        avaliable = Math.max(getDisplay().getHeight(),
+                mActivity.findViewById(android.R.id.content).getHeight()) - anchorView.getHeight();
         maxAvailableHeight = mPopupWindow.getMaxAvailableHeight(anchorView);
         assertTrue(maxAvailableHeight > 0);
         assertTrue(maxAvailableHeight <= avaliable);
diff --git a/tests/tests/widget/src/android/widget/cts/QuickContactBadgeTest.java b/tests/tests/widget/src/android/widget/cts/QuickContactBadgeTest.java
index cfd61a2..25d8e5e 100644
--- a/tests/tests/widget/src/android/widget/cts/QuickContactBadgeTest.java
+++ b/tests/tests/widget/src/android/widget/cts/QuickContactBadgeTest.java
@@ -21,8 +21,6 @@
 import android.content.ContextWrapper;
 import android.content.Intent;
 import android.net.Uri;
-import android.os.Bundle;
-import android.os.UserHandle;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.Contacts;
 import android.test.InstrumentationTestCase;
@@ -39,22 +37,12 @@
         final String plainMimeType = "text/plain";
         final Uri nonExistentContactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 0);
         final CountDownLatch latch = new CountDownLatch(1);
-        Context context = new ContextWrapper(getInstrumentation().getContext()) {
+        final Context context = new ContextWrapper(getInstrumentation().getContext()) {
             @Override
             public void startActivity(Intent intent) {
                 testCallback(intent);
             }
 
-            @Override
-            public void startActivityAsUser(Intent intent, UserHandle user) {
-                testCallback(intent);
-            }
-
-            @Override
-            public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) {
-                testCallback(intent);
-            }
-
             private void testCallback(Intent intent) {
                 assertEquals(plainMimeType, intent.getStringExtra(
                         ContactsContract.QuickContact.EXTRA_PRIORITIZED_MIMETYPE));
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
index 328f9f3..58738a1 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
@@ -16,6 +16,7 @@
 
 package android.widget.cts;
 
+import android.graphics.drawable.Icon;
 import android.test.UiThreadTest;
 import com.android.cts.widget.R;
 
@@ -152,6 +153,33 @@
         }
     }
 
+    public void testSetIcon() {
+        ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image);
+        assertNull(image.getDrawable());
+
+        Icon iconBlack = Icon.createWithResource(mActivity, R.drawable.icon_black);
+        mRemoteViews.setIcon(R.id.remoteView_image, "setImageIcon", iconBlack);
+        mRemoteViews.reapply(mActivity, mResult);
+        assertNotNull(image.getDrawable());
+        BitmapDrawable dBlack = (BitmapDrawable) mActivity.getDrawable(R.drawable.icon_black);
+        WidgetTestUtils.assertEquals(dBlack.getBitmap(),
+                ((BitmapDrawable) image.getDrawable()).getBitmap());
+    }
+
+    public void testSetImageViewIcon() {
+        ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image);
+        assertNull(image.getDrawable());
+
+        Icon iconBlue = Icon.createWithResource(mActivity, R.drawable.icon_blue);
+        mRemoteViews.setImageViewIcon(R.id.remoteView_image, iconBlue);
+        mRemoteViews.reapply(mActivity, mResult);
+        assertNotNull(image.getDrawable());
+        BitmapDrawable dBlue = (BitmapDrawable) mActivity.getDrawable(R.drawable.icon_blue);
+        WidgetTestUtils.assertEquals(dBlue.getBitmap(),
+                ((BitmapDrawable) image.getDrawable()).getBitmap());
+
+    }
+
     public void testSetImageViewResource() {
         ImageView image = (ImageView) mResult.findViewById(R.id.remoteView_image);
         assertNull(image.getDrawable());
@@ -159,8 +187,7 @@
         mRemoteViews.setImageViewResource(R.id.remoteView_image, R.drawable.testimage);
         mRemoteViews.reapply(mActivity, mResult);
         assertNotNull(image.getDrawable());
-        BitmapDrawable d = (BitmapDrawable) mActivity
-                .getResources().getDrawable(R.drawable.testimage);
+        BitmapDrawable d = (BitmapDrawable) mActivity.getDrawable(R.drawable.testimage);
         WidgetTestUtils.assertEquals(d.getBitmap(),
                 ((BitmapDrawable) image.getDrawable()).getBitmap());
 
diff --git a/tests/tests/widget/src/android/widget/cts/ResourceCursorAdapterTest.java b/tests/tests/widget/src/android/widget/cts/ResourceCursorAdapterTest.java
index 28bfd06..52d699b5 100644
--- a/tests/tests/widget/src/android/widget/cts/ResourceCursorAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ResourceCursorAdapterTest.java
@@ -170,13 +170,19 @@
     }
 
     private static class MockResourceCursorAdapter extends ResourceCursorAdapter {
+        private final boolean mAutoRequery;
+
         public MockResourceCursorAdapter(Context context, int layout, Cursor c) {
             super(context, layout, c);
+
+            mAutoRequery = false;
         }
 
         public MockResourceCursorAdapter(Context context, int layout,
                 Cursor c, boolean autoRequery) {
             super(context, layout, c, autoRequery);
+
+            mAutoRequery = autoRequery;
         }
 
         @Override
diff --git a/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java b/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java
index 5259736..b9f0d1f 100644
--- a/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java
@@ -18,7 +18,6 @@
 
 import com.android.cts.widget.R;
 
-
 import android.content.Context;
 import android.content.res.XmlResourceParser;
 import android.test.ActivityInstrumentationTestCase2;
diff --git a/tests/tests/widget/src/android/widget/cts/TableLayout_LayoutParamsTest.java b/tests/tests/widget/src/android/widget/cts/TableLayout_LayoutParamsTest.java
index 8a38c81..cbc41ce 100644
--- a/tests/tests/widget/src/android/widget/cts/TableLayout_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TableLayout_LayoutParamsTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.internal.R;
+import com.android.cts.widget.R;
 
 import org.xmlpull.v1.XmlPullParser;
 
@@ -140,8 +140,7 @@
         XmlResourceParser parser = null;
         AttributeSet attrs = null;
         try {
-            parser = mTargetContext.getResources()
-                    .getXml(com.android.cts.widget.R.xml.base_attributes);
+            parser = mTargetContext.getResources().getXml(R.xml.base_attributes);
 
             int type;
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
diff --git a/tests/tests/widget/src/android/widget/cts/TableRow_LayoutParamsTest.java b/tests/tests/widget/src/android/widget/cts/TableRow_LayoutParamsTest.java
index 06f851d..8308414 100644
--- a/tests/tests/widget/src/android/widget/cts/TableRow_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TableRow_LayoutParamsTest.java
@@ -16,7 +16,7 @@
 
 package android.widget.cts;
 
-import com.android.internal.R;
+import com.android.cts.widget.R;
 
 import org.xmlpull.v1.XmlPullParser;
 
@@ -91,8 +91,8 @@
         assertEquals(0, layoutParams.span);
 
         TableCtsActivity activity = getActivity();
-        activity.setContentView(com.android.cts.widget.R.layout.table_layout_2);
-        int idTable = com.android.cts.widget.R.id.table2;
+        activity.setContentView(R.layout.table_layout_2);
+        int idTable = R.id.table2;
         TableLayout tableLayout = (TableLayout) activity.findViewById(idTable);
         View vVitural1 = ((TableRow) tableLayout.getChildAt(0)).getVirtualChildAt(1);
         layoutParams = (TableRow.LayoutParams) vVitural1.getLayoutParams();
@@ -186,8 +186,7 @@
         XmlResourceParser parser = null;
         AttributeSet attrs = null;
         try {
-            parser = mTargetContext.getResources()
-                    .getXml(com.android.cts.widget.R.xml.base_attributes);
+            parser = mTargetContext.getResources().getXml(R.xml.base_attributes);
 
             int type;
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 31a4636..936f38f 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -17,7 +17,6 @@
 package android.widget.cts;
 
 import com.android.cts.widget.R;
-import com.android.internal.util.FastMath;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -786,37 +785,37 @@
         float add = 1.2f;
         float mult = 1.4f;
         setLineSpacing(add, mult);
-        assertEquals(FastMath.round(originalLineHeight * mult + add), mTextView.getLineHeight());
+        assertEquals(Math.round(originalLineHeight * mult + add), mTextView.getLineHeight());
         add = 0.0f;
         mult = 1.4f;
         setLineSpacing(add, mult);
-        assertEquals(FastMath.round(originalLineHeight * mult + add), mTextView.getLineHeight());
+        assertEquals(Math.round(originalLineHeight * mult + add), mTextView.getLineHeight());
 
         // abnormal
         add = -1.2f;
         mult = 1.4f;
         setLineSpacing(add, mult);
-        assertEquals(FastMath.round(originalLineHeight * mult + add), mTextView.getLineHeight());
+        assertEquals(Math.round(originalLineHeight * mult + add), mTextView.getLineHeight());
         add = -1.2f;
         mult = -1.4f;
         setLineSpacing(add, mult);
-        assertEquals(FastMath.round(originalLineHeight * mult + add), mTextView.getLineHeight());
+        assertEquals(Math.round(originalLineHeight * mult + add), mTextView.getLineHeight());
         add = 1.2f;
         mult = 0.0f;
         setLineSpacing(add, mult);
-        assertEquals(FastMath.round(originalLineHeight * mult + add), mTextView.getLineHeight());
+        assertEquals(Math.round(originalLineHeight * mult + add), mTextView.getLineHeight());
 
         // edge
         add = Float.MIN_VALUE;
         mult = Float.MIN_VALUE;
         setLineSpacing(add, mult);
         float expected = originalLineHeight * mult + add;
-        assertEquals(FastMath.round(expected), mTextView.getLineHeight());
+        assertEquals(Math.round(expected), mTextView.getLineHeight());
         add = Float.MAX_VALUE;
         mult = Float.MAX_VALUE;
         setLineSpacing(add, mult);
         expected = originalLineHeight * mult + add;
-        assertEquals(FastMath.round(expected), mTextView.getLineHeight());
+        assertEquals(Math.round(expected), mTextView.getLineHeight());
     }
 
     public void testInstanceState() {
diff --git a/tests/tests/widget/src/android/widget/cts/util/ListScenario.java b/tests/tests/widget/src/android/widget/cts/util/ListScenario.java
index 11d670d..b61673c 100644
--- a/tests/tests/widget/src/android/widget/cts/util/ListScenario.java
+++ b/tests/tests/widget/src/android/widget/cts/util/ListScenario.java
@@ -17,6 +17,7 @@
 package android.widget.cts.util;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -35,8 +36,6 @@
 import android.widget.ListView;
 import android.widget.TextView;
 
-import com.google.android.collect.Maps;
-
 /**
  * Utility base class for creating various List scenarios.  Configurable by the number
  * of items, how tall each item should be (in relation to the screen height), and
@@ -52,7 +51,7 @@
 
     private int mStartingSelectionPosition;
     private double mItemScreenSizeFactor;
-    private Map<Integer, Double> mOverrideItemScreenSizeFactors = Maps.newHashMap();
+    private Map<Integer, Double> mOverrideItemScreenSizeFactors = new HashMap<>();
 
     private int mScreenHeight;
 
@@ -102,7 +101,7 @@
         private double mItemScreenSizeFactor = 1 / 5;
         private Double mFadingEdgeScreenSizeFactor = null;
 
-        private Map<Integer, Double> mOverrideItemScreenSizeFactors = Maps.newHashMap();
+        private Map<Integer, Double> mOverrideItemScreenSizeFactors = new HashMap<>();
 
         // separators
         private List<Integer> mUnselectableItems = new ArrayList<Integer>(8);
diff --git a/tests/tests/widget/src/android/widget/cts/util/XmlUtils.java b/tests/tests/widget/src/android/widget/cts/util/XmlUtils.java
index c357e5e..1ff922f 100644
--- a/tests/tests/widget/src/android/widget/cts/util/XmlUtils.java
+++ b/tests/tests/widget/src/android/widget/cts/util/XmlUtils.java
@@ -16,8 +16,6 @@
 
 package android.widget.cts.util;
 
-import com.android.internal.util.FastXmlSerializer;
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -171,28 +169,6 @@
     }
 
     /**
-     * Flatten a Map into an output stream as XML.  The map can later be
-     * read back with readMapXml().
-     *
-     * @param val The map to be flattened.
-     * @param out Where to write the XML data.
-     *
-     * @see #writeMapXml(Map, String, XmlSerializer)
-     * @see #writeListXml
-     * @see #writeValueXml
-     * @see #readMapXml
-     */
-    public static final void writeMapXml(Map val, OutputStream out)
-            throws XmlPullParserException, IOException {
-        XmlSerializer serializer = new FastXmlSerializer();
-        serializer.setOutput(out, StandardCharsets.UTF_8.name());
-        serializer.startDocument(null, true);
-        serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-        writeMapXml(val, null, serializer);
-        serializer.endDocument();
-    }
-
-    /**
      * Flatten a List into an output stream as XML.  The list can later be
      * read back with readListXml().
      *
@@ -224,7 +200,6 @@
      *             none.
      * @param out XmlSerializer to write the map into.
      *
-     * @see #writeMapXml(Map, OutputStream)
      * @see #writeListXml
      * @see #writeValueXml
      * @see #readMapXml
@@ -244,7 +219,6 @@
      * @param out XmlSerializer to write the map into.
      * @param callback Method to call when an Object type is not recognized.
      *
-     * @see #writeMapXml(Map, OutputStream)
      * @see #writeListXml
      * @see #writeValueXml
      * @see #readMapXml
@@ -278,7 +252,6 @@
      * @param val The map to be flattened.
      * @param out XmlSerializer to write the map into.
      *
-     * @see #writeMapXml(Map, OutputStream)
      * @see #writeListXml
      * @see #writeValueXml
      * @see #readMapXml