Merge "[RenderScript] Guard rsDebug calls with a runtime check" into nyc-dev
diff --git a/OldCtsTestCaseList.mk b/OldCtsTestCaseList.mk
index 6b30aee..2e7de5e 100644
--- a/OldCtsTestCaseList.mk
+++ b/OldCtsTestCaseList.mk
@@ -76,6 +76,7 @@
     CtsUnaffiliatedAccountAuthenticators
 
 cts_support_packages := \
+    CtsAbiOverrideTestApp \
     CtsAccountManagementDevicePolicyApp \
     CtsAlarmClockService \
     CtsAppRestrictionsManagingApp \
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index cf3d55a..79e8a36 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -29,6 +29,7 @@
                                android-support-v4 \
                                compatibility-common-util-devicesidelib \
                                cts-sensors-tests \
+                               cts-location-tests \
                                ctstestrunner \
                                apache-commons-math \
                                androidplot \
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 107b0eb..5d3914f 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -23,6 +23,7 @@
     <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="24"/>
 
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.BLUETOOTH" />
@@ -437,6 +438,50 @@
             <meta-data android:name="test_required_features" android:value="android.hardware.location.gps" />
         </activity>
 
+        <activity android:name=".location.GnssMeasurementRegistrationTestsActivity"
+            android:label="@string/location_gnss_reg_test"
+            android:screenOrientation="locked">
+            <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_hardware"/>
+            <meta-data android:name="test_required_features" android:value="android.hardware.location.gps" />
+        </activity>
+
+        <activity android:name=".location.GnssMeasurementValuesTestsActivity"
+            android:label="@string/location_gnss_value_test"
+            android:screenOrientation="locked">
+            <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_hardware"/>
+            <meta-data android:name="test_required_features" android:value="android.hardware.location.gps" />
+        </activity>
+
+        <activity android:name=".location.GnssMeasurementWhenNoLocationTestsActivity"
+            android:label="@string/location_gnss_measure_no_location_test"
+            android:screenOrientation="locked">
+            <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_hardware"/>
+            <meta-data android:name="test_required_features" android:value="android.hardware.location.gps" />
+        </activity>
+
+        <activity android:name=".location.GnssNavigationMessageTestsActivity"
+            android:label="@string/location_gnss_nav_msg_test"
+            android:screenOrientation="locked">
+            <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_hardware"/>
+            <meta-data android:name="test_required_features" android:value="android.hardware.location.gps" />
+        </activity>
+
         <activity android:name=".location.LocationListenerActivity"
                 android:label="@string/location_listener_activity"
                 android:configChanges="keyboardHidden|orientation|screenSize">
diff --git a/apps/CtsVerifier/proguard.flags b/apps/CtsVerifier/proguard.flags
index 591d3db..187e8d2 100644
--- a/apps/CtsVerifier/proguard.flags
+++ b/apps/CtsVerifier/proguard.flags
@@ -14,6 +14,14 @@
     public <methods>;
 }
 
+# ensure we keep public Gnss Measurement test methods, these are needed at runtime
+-keepclassmembers class * extends com.android.cts.verifier.location.BaseGnssTestActivity {
+    public <methods>;
+}
+-keepclassmembers class * extends android.location.cts.GnssTestCase {
+    public <methods>;
+}
+
 -keepclasseswithmembers class * extends com.android.cts.verifier.location.LocationModeTestActivity
 
 # keep mockito methods
@@ -34,3 +42,4 @@
 -dontwarn com.android.okhttp.**
 -dontwarn org.opencv.**
 -dontwarn android.support.test.internal.runner.hidden.ExposedInstrumentationApi
+
diff --git a/apps/CtsVerifier/res/layout-land/gnss_test.xml b/apps/CtsVerifier/res/layout-land/gnss_test.xml
new file mode 100644
index 0000000..c511d40
--- /dev/null
+++ b/apps/CtsVerifier/res/layout-land/gnss_test.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.cts.verifier.BoxInsetLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <LinearLayout app:ctsv_layout_box="all"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        >
+
+        <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1">
+
+            <TextView android:id="@+id/text"
+                android:textSize="14sp"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"/>
+
+            <ScrollView
+                android:id="@+id/log_scroll_view"
+                android:fillViewport="true"
+                android:layout_height="match_parent"
+                android:layout_width="0dp"
+                android:layout_weight="1">
+
+                <LinearLayout
+                    android:id="@+id/log_layout"
+                    android:orientation="vertical"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"/>
+            </ScrollView>
+
+        </LinearLayout>
+
+        <include layout="@layout/snsr_next_button" />
+
+    </LinearLayout>
+</com.android.cts.verifier.BoxInsetLayout>
diff --git a/apps/CtsVerifier/res/layout-port/gnss_test.xml b/apps/CtsVerifier/res/layout-port/gnss_test.xml
new file mode 100644
index 0000000..560133a
--- /dev/null
+++ b/apps/CtsVerifier/res/layout-port/gnss_test.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.cts.verifier.BoxInsetLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <LinearLayout app:ctsv_layout_box="all"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        >
+
+        <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1">
+
+            <TextView android:id="@+id/text"
+                android:textSize="14sp"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"/>
+
+            <ScrollView
+                android:id="@+id/log_scroll_view"
+                android:fillViewport="true"
+                android:layout_height="match_parent"
+                android:layout_width="0dp"
+                android:layout_weight="1">
+
+                <LinearLayout
+                    android:id="@+id/log_layout"
+                    android:orientation="vertical"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"/>
+
+            </ScrollView>
+
+        </LinearLayout>
+
+        <include layout="@layout/snsr_next_button" />
+
+    </LinearLayout>
+</com.android.cts.verifier.BoxInsetLayout>
diff --git a/apps/CtsVerifier/res/layout-small/gnss_test.xml b/apps/CtsVerifier/res/layout-small/gnss_test.xml
new file mode 100644
index 0000000..5caea07
--- /dev/null
+++ b/apps/CtsVerifier/res/layout-small/gnss_test.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.cts.verifier.BoxInsetLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <ScrollView android:id="@+id/log_scroll_view"
+        app:ctsv_layout_box="all"
+        android:fillViewport="true"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent">
+        <LinearLayout
+            android:orientation="vertical"
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent">
+
+            <TextView android:id="@+id/text"
+                android:textSize="14sp"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"/>
+
+            <LinearLayout android:id="@+id/log_layout"
+                android:orientation="vertical"
+                android:layout_height="wrap_content"
+                android:layout_width="match_parent"/>
+
+            <include layout="@layout/snsr_next_button"/>
+        </LinearLayout>
+
+    </ScrollView>
+</com.android.cts.verifier.BoxInsetLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 8712a5b..50e1bdf 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -417,6 +417,17 @@
         and then press OK to run the automated tests.</string>
     <string name="location_listener_activity">Location listener</string>
 
+    <!-- Strings for Location GNSS tests -->
+    <string name="location_gnss_measure_no_location_test">GNSS Measurement WhenNoLocation Test</string>
+    <string name="location_gnss_reg_test">GNSS Measurement Registration Test</string>
+    <string name="location_gnss_value_test">GNSS Measurement Values Test</string>
+    <string name="location_gnss_nav_msg_test">GNSS Navigation Message Test</string>
+    <string name="location_gnss_test_info">This test verifies basic GNSS behavior.
+        Make sure the device has line of sight to GNSS satellites
+        (for example, stationary on a windowsill.  If needed, try again, outside, also with the
+        device stationary, and with at least some view of the sky.) and then press Next to run
+        the automated tests.</string>
+
     <!-- Strings for net.ConnectivityScreenOffTestActivity -->
     <string name="network_screen_off_test">Network Connectivity Screen Off Test</string>
     <string name="network_screen_off_test_instructions">
@@ -2070,6 +2081,16 @@
             Also, check that if you can download files from your phone to the desktop computer. The test is successful if the files from your phone are not and cannot be downloaded through USB.\n
             Please mark the test accordingly.
     </string>
+    <string name="device_owner_set_user_icon">Setting the user icon</string>
+    <string name="device_owner_set_user_icon_instruction">
+        This test verifies that the user icon can be set.\n
+        1. Press the set user icon button.\n
+        2. Press the go button to go to Settings.\n
+        3a. If there is a \"users\" section in Settings, check that the icon of the user \"owner\" is the CtsVerifier one and mark this test accordingly.\n
+        3b. If there is no \"users\" section, mark this test as passed.\n
+    </string>
+    <string name="device_owner_set_user_icon_button">Set user icon</string>
+
     <string name="profile_owner_permission_lockdown_test_info">
         <b>
         Before proceeding, check if com.android.cts.permissionapp (aka CtsPermissionApp) is installed in work profile by going to Settings &gt; Apps. If not, please install the app before proceeding.\n\n
@@ -2441,6 +2462,13 @@
     Do you see the programs named \"Dummy Program\" and their descriptions
     "Dummy Program Description" in the EPG?
     </string>
+    <string name="tv_input_discover_test_trigger_setup">
+    Select the \"Launch setup\" button and verify if the bundled TV app shows the list of installed
+    TV inputs for setup.
+    </string>
+    <string name="tv_input_discover_test_verify_trigger_setup">
+    Do you see the \"CTS Verifier\" input in the list?
+    </string>
 
     <string name="tv_parental_control_test">TV app parental controls test</string>
     <string name="tv_parental_control_test_info">
@@ -2468,6 +2496,7 @@
 
     <string name="tv_launch_tv_app">Launch TV app</string>
     <string name="tv_launch_epg">Launch EPG</string>
+    <string name="tv_launch_setup">Launch setup</string>
     <string name="tv_channel_not_found">
     CtsVerifier channel is not set up. Please set up before proceeding.
     </string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssMeasurementRegistrationTestsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssMeasurementRegistrationTestsActivity.java
new file mode 100644
index 0000000..56755cc
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssMeasurementRegistrationTestsActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.verifier.location;
+
+import android.location.cts.GnssMeasurementRegistrationTest;
+import com.android.cts.verifier.location.base.GnssCtsTestActivity;
+
+/**
+ * Activity to execute CTS Gnss Measurement tests.
+ * It is a wrapper for {@link GnssMeasurementValuesTest} running with AndroidJUnitRunner.
+ */
+public class GnssMeasurementRegistrationTestsActivity extends GnssCtsTestActivity {
+    public GnssMeasurementRegistrationTestsActivity() {
+        super(GnssMeasurementRegistrationTest.class);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssMeasurementValuesTestsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssMeasurementValuesTestsActivity.java
new file mode 100644
index 0000000..4bdbddf
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssMeasurementValuesTestsActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.verifier.location;
+
+import android.location.cts.GnssMeasurementValuesTest;
+import com.android.cts.verifier.location.base.GnssCtsTestActivity;
+
+/**
+ * Activity to execute CTS Gnss Measurement tests.
+ * It is a wrapper for {@link GnssMeasurementValuesTest} running with AndroidJUnitRunner.
+ */
+public class GnssMeasurementValuesTestsActivity extends GnssCtsTestActivity {
+    public GnssMeasurementValuesTestsActivity() {
+        super(GnssMeasurementValuesTest.class);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssMeasurementWhenNoLocationTestsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssMeasurementWhenNoLocationTestsActivity.java
new file mode 100644
index 0000000..1ee74c5
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssMeasurementWhenNoLocationTestsActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.verifier.location;
+
+import android.location.cts.GnssMeasurementWhenNoLocationTest;
+import com.android.cts.verifier.location.base.GnssCtsTestActivity;
+
+/**
+ * Activity to execute CTS GnssMeasurementWhenNoLocationTest.
+ * It is a wrapper for {@link GnssMeasurementValuesTest} running with AndroidJUnitRunner.
+ */
+public class GnssMeasurementWhenNoLocationTestsActivity extends GnssCtsTestActivity {
+    public GnssMeasurementWhenNoLocationTestsActivity() {
+        super(GnssMeasurementWhenNoLocationTest.class);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssNavigationMessageTestsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssNavigationMessageTestsActivity.java
new file mode 100644
index 0000000..a4c9c93
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssNavigationMessageTestsActivity.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.verifier.location;
+
+import android.location.cts.GnssNavigationMessageTest;
+import com.android.cts.verifier.location.base.GnssCtsTestActivity;
+
+/**
+ * Activity to execute CTS GnssNavigationMessageTest.
+ * It is a wrapper for {@link GnssMeasurementValuesTest} running with AndroidJUnitRunner.
+ */
+public class GnssNavigationMessageTestsActivity extends GnssCtsTestActivity {
+    public GnssNavigationMessageTestsActivity() {
+        super(GnssNavigationMessageTest.class);
+    }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/base/BaseGnssTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/BaseGnssTestActivity.java
new file mode 100644
index 0000000..6c626fb
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/BaseGnssTestActivity.java
@@ -0,0 +1,463 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.verifier.location.base;
+
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.TestResult;
+import com.android.cts.verifier.location.reporting.GnssTestDetails;
+
+import junit.framework.Assert;
+
+import com.android.cts.verifier.PassFailButtons;
+
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.cts.helpers.ActivityResultMultiplexedLatch;
+import android.media.MediaPlayer;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.os.Vibrator;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import android.test.AndroidTestCase;
+
+/**
+ * A base Activity that is used to build different methods to execute tests inside CtsVerifier.
+ * i.e. CTS tests, and semi-automated CtsVerifier tests.
+ *
+ * This class provides access to the following flow:
+ *      Activity set up
+ *          Execute tests (implemented by sub-classes)
+ *      Activity clean up
+ *
+ * Currently the following class structure is available:
+ * - BaseGnssTestActivity                 : provides the platform to execute Gnss tests inside
+ *      |                                     CtsVerifier.
+ *      |
+ *      -- GnssCtsTestActivity            : an activity that can be inherited from to wrap a CTS
+ *      |                                     Gnss test, and execute it inside CtsVerifier
+ *      |                                     these tests do not require any operator interaction
+ */
+public abstract class BaseGnssTestActivity extends PassFailButtons.Activity
+        implements View.OnClickListener, Runnable, IGnssTestStateContainer {
+    @Deprecated
+    protected static final String LOG_TAG = "GnssTest";
+
+    protected final Class mTestClass;
+
+    private final int mLayoutId;
+
+    private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
+    private final ActivityResultMultiplexedLatch mActivityResultMultiplexedLatch =
+            new ActivityResultMultiplexedLatch();
+    private final ArrayList<CountDownLatch> mWaitForUserLatches = new ArrayList<CountDownLatch>();
+
+    private ScrollView mLogScrollView;
+    private LinearLayout mLogLayout;
+    private Button mNextButton;
+    private Button mPassButton;
+    private Button mFailButton;
+    protected TextView mTextView;
+
+    /**
+     * Constructor to be used by subclasses.
+     *
+     * @param testClass The class that contains the tests. It is dependant on test executor
+     *                  implemented by subclasses.
+     */
+    protected BaseGnssTestActivity(Class<? extends AndroidTestCase> testClass) {
+        this(testClass, R.layout.gnss_test);
+    }
+
+    /**
+     * Constructor to be used by subclasses. It allows to provide a custom layout for the test UI.
+     *
+     * @param testClass The class that contains the tests. It is dependant on test executor
+     *                  implemented by subclasses.
+     * @param layoutId The Id of the layout to use for the test UI. The layout must contain all the
+     *                 elements in the base layout {@code R.layout.gnss_test}.
+     */
+    protected BaseGnssTestActivity(Class testClass, int layoutId) {
+        mTestClass = testClass;
+        mLayoutId = layoutId;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(mLayoutId);
+
+        mLogScrollView = (ScrollView) findViewById(R.id.log_scroll_view);
+        mLogLayout = (LinearLayout) findViewById(R.id.log_layout);
+        mNextButton = (Button) findViewById(R.id.next_button);
+        mNextButton.setOnClickListener(this);
+        mPassButton = (Button) findViewById(R.id.pass_button);
+        mFailButton = (Button) findViewById(R.id.fail_button);
+        mTextView = (TextView) findViewById(R.id.text);
+
+        mTextView.setText(R.string.location_gnss_test_info);
+
+        updateNextButton(false /*enabled*/);
+        mExecutorService.execute(this);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mExecutorService.shutdownNow();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    public void onClick(View target) {
+        synchronized (mWaitForUserLatches) {
+            for (CountDownLatch latch : mWaitForUserLatches) {
+                latch.countDown();
+            }
+            mWaitForUserLatches.clear();
+        }
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        mActivityResultMultiplexedLatch.onActivityResult(requestCode, resultCode);
+    }
+
+    /**
+     * The main execution {@link Thread}.
+     *
+     * This function executes in a background thread, allowing the test run freely behind the
+     * scenes. It provides the following execution hooks:
+     *  - Activity SetUp/CleanUp (not available in JUnit)
+     *  - executeTests: to implement several execution engines
+     */
+    @Override
+    public void run() {
+        long startTimeNs = SystemClock.elapsedRealtimeNanos();
+        String testName = getTestClassName();
+
+        GnssTestDetails testDetails;
+        try {
+            testDetails = new GnssTestDetails(testName, GnssTestDetails.ResultCode.PASS);
+        } catch (Throwable e) {
+            testDetails = new GnssTestDetails(testName, "DeactivateFeatures", e);
+        }
+
+        GnssTestDetails.ResultCode resultCode = testDetails.getResultCode();
+        if (resultCode == GnssTestDetails.ResultCode.SKIPPED) {
+            // this is an invalid state at this point of the test setup
+            throw new IllegalStateException("Deactivation of features cannot skip the test.");
+        }
+        if (resultCode == GnssTestDetails.ResultCode.PASS) {
+            testDetails = executeActivityTests(testName);
+        }
+    }
+
+    /**
+     * A general set up routine. It executes only once before the first test case.
+     *
+     * NOTE: implementers must be aware of the interrupted status of the worker thread, and let
+     * {@link InterruptedException} propagate.
+     *
+     * @throws Throwable An exception that denotes the failure of set up. No tests will be executed.
+     */
+    protected void activitySetUp() throws Throwable {}
+
+    /**
+     * A general clean up routine. It executes upon successful execution of {@link #activitySetUp()}
+     * and after all the test cases.
+     *
+     * NOTE: implementers must be aware of the interrupted status of the worker thread, and handle
+     * it in two cases:
+     * - let {@link InterruptedException} propagate
+     * - if it is invoked with the interrupted status, prevent from showing any UI
+
+     * @throws Throwable An exception that will be logged and ignored, for ease of implementation
+     *                   by subclasses.
+     */
+    protected void activityCleanUp() throws Throwable {}
+
+    /**
+     * Performs the work of executing the tests.
+     * Sub-classes implementing different execution methods implement this method.
+     *
+     * @return A {@link GnssTestDetails} object containing information about the executed tests.
+     */
+    protected abstract GnssTestDetails executeTests() throws InterruptedException;
+
+    @Deprecated
+    protected void appendText(String text) {
+        TextAppender textAppender = new TextAppender(R.layout.snsr_instruction);
+        textAppender.setText(text);
+        textAppender.append();
+    }
+
+    @Deprecated
+    protected void clearText() {
+        this.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mLogLayout.removeAllViews();
+            }
+        });
+    }
+
+    /**
+     * Waits for the operator to acknowledge a requested action.
+     *
+     * @param waitMessageResId The action requested to the operator.
+     */
+    protected void waitForUser(int waitMessageResId) throws InterruptedException {
+        CountDownLatch latch = new CountDownLatch(1);
+        synchronized (mWaitForUserLatches) {
+            mWaitForUserLatches.add(latch);
+        }
+
+        updateNextButton(true);
+        latch.await();
+        updateNextButton(false);
+    }
+
+    /**
+     * Waits for the operator to acknowledge to begin execution.
+     */
+    protected void waitForUserToBegin() throws InterruptedException {
+        waitForUser(R.string.snsr_wait_to_begin);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void waitForUserToContinue() throws InterruptedException {
+        waitForUser(R.string.snsr_wait_for_user);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int executeActivity(String action) throws InterruptedException {
+        return executeActivity(new Intent(action));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int executeActivity(Intent intent) throws InterruptedException {
+        ActivityResultMultiplexedLatch.Latch latch = mActivityResultMultiplexedLatch.bindThread();
+        startActivityForResult(intent, latch.getRequestCode());
+        return latch.await();
+    }
+
+    /**
+     * Plays a (default) sound as a notification for the operator.
+     */
+    protected void playSound() throws InterruptedException {
+        MediaPlayer player = MediaPlayer.create(this, Settings.System.DEFAULT_NOTIFICATION_URI);
+        if (player == null) {
+            Log.e(LOG_TAG, "MediaPlayer unavailable.");
+            return;
+        }
+        player.start();
+        try {
+            Thread.sleep(500);
+        } finally {
+            player.stop();
+        }
+    }
+
+    /**
+     * Makes the device vibrate for the given amount of time.
+     */
+    protected void vibrate(int timeInMs) {
+        Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
+        vibrator.vibrate(timeInMs);
+    }
+
+    /**
+     * Makes the device vibrate following the given pattern.
+     * See {@link Vibrator#vibrate(long[], int)} for more information.
+     */
+    protected void vibrate(long[] pattern) {
+        Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
+        vibrator.vibrate(pattern, -1);
+    }
+
+    protected String getTestClassName() {
+        if (mTestClass == null) {
+            return "<unknown>";
+        }
+        return mTestClass.getName();
+    }
+
+    protected void setLogScrollViewListener(View.OnTouchListener listener) {
+        mLogScrollView.setOnTouchListener(listener);
+    }
+
+    private void setTestResult(GnssTestDetails testDetails) {
+        // the name here, must be the Activity's name because it is what CtsVerifier expects
+        String name = super.getClass().getName();
+        //String summary = mTestLogger.getOverallSummary();
+        GnssTestDetails.ResultCode resultCode = testDetails.getResultCode();
+        switch(resultCode) {
+            case SKIPPED:
+                TestResult.setPassedResult(this, name, "");
+                break;
+            case PASS:
+                TestResult.setPassedResult(this, name, "");
+                break;
+            case FAIL:
+                TestResult.setFailedResult(this, name, "");
+                break;
+            case INTERRUPTED:
+                // do not set a result, just return so the test can complete
+                break;
+            default:
+                throw new IllegalStateException("Unknown ResultCode: " + resultCode);
+        }
+    }
+
+    private GnssTestDetails executeActivityTests(String testName) {
+        GnssTestDetails testDetails;
+        try {
+            activitySetUp();
+            testDetails = new GnssTestDetails(testName, GnssTestDetails.ResultCode.PASS);
+        } catch (Throwable e) {
+            testDetails = new GnssTestDetails(testName, "ActivitySetUp", e);
+        }
+
+        GnssTestDetails.ResultCode resultCode = testDetails.getResultCode();
+        if (resultCode == GnssTestDetails.ResultCode.PASS) {
+            // TODO: implement execution filters:
+            //      - execute all tests and report results officially
+            //      - execute single test or failed tests only
+            try {
+                testDetails = executeTests();
+            } catch (Throwable e) {
+                // we catch and continue because we have to guarantee a proper clean-up sequence
+                testDetails = new GnssTestDetails(testName, "TestExecution", e);
+            }
+        }
+
+        // clean-up executes for all states, even on SKIPPED and INTERRUPTED there might be some
+        // intermediate state that needs to be taken care of
+        try {
+            activityCleanUp();
+        } catch (Throwable e) {
+            testDetails = new GnssTestDetails(testName, "ActivityCleanUp", e);
+        }
+
+        return testDetails;
+    }
+
+    private void updateNextButton(final boolean enabled) {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mNextButton.setEnabled(enabled);
+            }
+        });
+    }
+
+    private void enableTestResultButton(
+            final Button button,
+            final int textResId,
+            final GnssTestDetails testDetails) {
+        final View.OnClickListener listener = new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                setTestResult(testDetails);
+                finish();
+            }
+        };
+
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mNextButton.setVisibility(View.GONE);
+                button.setText(textResId);
+                button.setOnClickListener(listener);
+                button.setVisibility(View.VISIBLE);
+            }
+        });
+    }
+
+    private class ViewAppender {
+        protected final View mView;
+
+        public ViewAppender(View view) {
+            mView = view;
+        }
+
+        public void append() {
+            runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    mLogLayout.addView(mView);
+                    mLogScrollView.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            mLogScrollView.fullScroll(View.FOCUS_DOWN);
+                        }
+                    });
+                }
+            });
+        }
+    }
+
+    private class TextAppender extends ViewAppender{
+        private final TextView mTextView;
+
+        public TextAppender(int textViewResId) {
+            super(getLayoutInflater().inflate(textViewResId, null /* viewGroup */));
+            mTextView = (TextView) mView;
+        }
+
+        public void setText(String text) {
+            mTextView.setText(text);
+        }
+
+        public void setText(int textResId) {
+            mTextView.setText(textResId);
+        }
+    }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/base/GnssCtsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/GnssCtsTestActivity.java
new file mode 100644
index 0000000..db955ba
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/GnssCtsTestActivity.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.verifier.location.base;
+
+import com.android.cts.verifier.R;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.junit.internal.runners.JUnit38ClassRunner;
+import org.junit.internal.runners.SuiteMethod;
+import org.junit.runner.Computer;
+import org.junit.runner.Description;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+import org.junit.runner.Runner;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.RunnerBuilder;
+
+import android.content.Context;
+import android.os.PowerManager;
+import android.view.WindowManager;
+
+import java.lang.Override;
+import java.lang.Runnable;
+import java.util.concurrent.TimeUnit;
+
+import android.location.cts.GnssTestCase;
+import com.android.cts.verifier.location.reporting.GnssTestDetails;
+
+/**
+ * An Activity that allows Gnss CTS tests to be executed inside CtsVerifier.
+ *
+ * Sub-classes pass the test class as part of construction.
+ * One JUnit test class is executed per Activity, the test class can still be executed outside
+ * CtsVerifier.
+ */
+public class GnssCtsTestActivity extends BaseGnssTestActivity {
+
+    /**
+     * Constructor for a CTS test executor. It will execute a standalone CTS test class.
+     *
+     * @param testClass The test class to execute, it must be a subclass of {@link AndroidTestCase}.
+     */
+    protected GnssCtsTestActivity(Class<? extends GnssTestCase> testClass) {
+        super(testClass);
+    }
+
+    @Override
+    protected void activitySetUp() throws InterruptedException {
+        waitForUserToBegin();
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mTextView.setText("Running test... \n");
+            }
+        });
+    }
+
+    @Override
+    protected void activityCleanUp() {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+            }
+        });
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+    }
+
+    /**
+     * For reference on the implementation of this test executor see:
+     *      android.support.test.runner.AndroidJUnitRunner
+     */
+    @Override
+    protected GnssTestDetails executeTests() {
+        JUnitCore testRunner = new JUnitCore();
+        testRunner.addListener(new GnssRunListener());
+
+        Computer computer = new Computer();
+        RunnerBuilder runnerBuilder = new GnssRunnerBuilder();
+
+        Runner runner;
+        try {
+            runner = computer.getSuite(runnerBuilder, new Class[]{ mTestClass });
+        } catch (Exception e) {
+            return new GnssTestDetails(
+                    getTestClassName(),
+                    GnssTestDetails.ResultCode.FAIL,
+                    "[JUnit Initialization]" + e.getMessage());
+        }
+
+        Request request = Request.runner(runner);
+        Result result = testRunner.run(request);
+        return new GnssTestDetails(getApplicationContext(), getClass().getName(), result);
+    }
+
+    /**
+     * A {@link RunnerBuilder} that is used to inject during execution a {@link GnssCtsTestSuite}.
+     */
+    private class GnssRunnerBuilder extends RunnerBuilder {
+        @Override
+        public Runner runnerForClass(Class<?> testClass) throws Throwable {
+            TestSuite testSuite;
+            if (hasSuiteMethod(testClass)) {
+                Test test = SuiteMethod.testFromSuiteMethod(testClass);
+                if (test instanceof TestSuite) {
+                    testSuite = (TestSuite) test;
+                } else {
+                    throw new IllegalArgumentException(
+                            testClass.getName() + "#suite() did not return a TestSuite.");
+                }
+            } else {
+                testSuite = new TestSuite(testClass);
+            }
+            GnssCtsTestSuite gnssTestSuite =
+                    new GnssCtsTestSuite(getApplicationContext(), testSuite);
+            return new JUnit38ClassRunner(gnssTestSuite);
+        }
+
+        private boolean hasSuiteMethod(Class<?> testClass) {
+            try {
+                testClass.getMethod("suite");
+                return true;
+            } catch (NoSuchMethodException e) {
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Dummy {@link RunListener}.
+     * It is only used to handle logging into the UI.
+     */
+    private class GnssRunListener extends RunListener {
+        private volatile boolean mCurrentTestReported;
+
+        public void testRunStarted(Description description) throws Exception {
+            // nothing to log
+        }
+
+        public void testRunFinished(Result result) throws Exception {
+            // nothing to log
+            vibrate((int)TimeUnit.SECONDS.toMillis(2));
+            playSound();
+        }
+
+        public void testStarted(Description description) throws Exception {
+            mCurrentTestReported = false;
+        }
+
+        public void testFinished(Description description) throws Exception {
+            if (!mCurrentTestReported) {
+                runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        mTextView.append("\n Test passed: " + description.getMethodName());
+                    }
+                });
+            }
+        }
+
+        public void testFailure(Failure failure) throws Exception {
+            mCurrentTestReported = true;
+            runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    mTextView.setText(""); // clear running status
+                    mTextView.append("\n Test failed: " + failure.getDescription().getMethodName()
+                            + "\n Error: " + failure.toString());
+                }
+            });
+        }
+
+        public void testAssumptionFailure(Failure failure) {
+            mCurrentTestReported = true;
+
+        }
+
+        public void testIgnored(Description description) throws Exception {
+            mCurrentTestReported = true;
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/base/GnssCtsTestResult.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/GnssCtsTestResult.java
new file mode 100644
index 0000000..6bb7ffc
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/GnssCtsTestResult.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.verifier.location.base;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Protectable;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestFailure;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+
+import android.content.Context;
+import android.test.AndroidTestCase;
+
+import java.util.Enumeration;
+
+/**
+ * A wrapper class for a {@link TestResult}.
+ *
+ * It provides a way to inject augmented data and helper objects during the execution of tests.
+ * i.e. inject a Context object for use by tests.
+ */
+public class GnssCtsTestResult extends TestResult {
+    private final Context mContext;
+    private final TestResult mWrappedTestResult;
+
+    private volatile boolean mInterrupted;
+
+    public GnssCtsTestResult(Context context, TestResult testResult) {
+        mContext = context;
+        mWrappedTestResult = testResult;
+    }
+
+    @Override
+    public void addError(Test test, Throwable throwable) {
+        mWrappedTestResult.addError(test, throwable);
+    }
+
+    @Override
+    public void addFailure(Test test, AssertionFailedError assertionFailedError) {
+        mWrappedTestResult.addFailure(test, assertionFailedError);
+    }
+
+    @Override
+    public void addListener(TestListener testListener) {
+        mWrappedTestResult.addListener(testListener);
+    }
+
+    @Override
+    public void removeListener(TestListener testListener) {
+        mWrappedTestResult.removeListener(testListener);
+    }
+
+    @Override
+    public void endTest(Test test) {
+        mWrappedTestResult.endTest(test);
+    }
+
+    @Override
+    public int errorCount() {
+        return mWrappedTestResult.errorCount();
+    }
+
+    @Override
+    public Enumeration<TestFailure> errors() {
+        return mWrappedTestResult.errors();
+    }
+
+    @Override
+    public int failureCount() {
+        return mWrappedTestResult.failureCount();
+    }
+
+    @Override
+    public Enumeration<TestFailure> failures() {
+        return mWrappedTestResult.failures();
+    }
+
+    @Override
+    public int runCount() {
+        return mWrappedTestResult.runCount();
+    }
+
+    @Override
+    public void runProtected(Test test, Protectable protectable) {
+        try {
+            protectable.protect();
+        } catch (AssertionFailedError e) {
+            addFailure(test, e);
+        } catch (ThreadDeath e) {
+            throw e;
+        } catch (InterruptedException e) {
+            mInterrupted = true;
+            addError(test, e);
+        } catch (Throwable e) {
+            addError(test, e);
+        }
+    }
+
+    @Override
+    public boolean shouldStop() {
+        return mInterrupted || mWrappedTestResult.shouldStop();
+    }
+
+    @Override
+    public void startTest(Test test) {
+        mWrappedTestResult.startTest(test);
+    }
+
+    @Override
+    public void stop() {
+        mWrappedTestResult.stop();
+    }
+
+    @Override
+    public boolean wasSuccessful() {
+        return mWrappedTestResult.wasSuccessful();
+    }
+
+    @Override
+    protected void run(TestCase testCase) {
+        if (testCase instanceof AndroidTestCase) {
+            AndroidTestCase gnssTestCase = (AndroidTestCase) testCase;
+            gnssTestCase.setContext(mContext);
+            //sensorTestCase.setEmulateSensorUnderLoad(false);
+            //sensorTestCase.setCurrentTestNode(new TestNode(testCase));
+            // TODO: set delayed assertion provider
+        } else {
+            throw new IllegalStateException("TestCase invalid.");
+        }
+        super.run(testCase);
+    }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/base/GnssCtsTestSuite.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/GnssCtsTestSuite.java
new file mode 100644
index 0000000..0a724b6
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/GnssCtsTestSuite.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.verifier.location.base;
+
+import junit.framework.Test;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+import android.content.Context;
+
+import java.util.Enumeration;
+
+/**
+ * A wrapper class for a {@link TestSuite}.
+ *
+ * It provides a way to inject a {@link GnssCtsTestResult} during execution.
+ */
+public class GnssCtsTestSuite extends TestSuite {
+    private final Context mContext;
+    private final TestSuite mWrappedTestSuite;
+
+    public GnssCtsTestSuite(Context context, TestSuite testSuite) {
+        mContext = context;
+        mWrappedTestSuite = testSuite;
+    }
+
+    @Override
+    public void run(TestResult testResult) {
+        mWrappedTestSuite.run(new GnssCtsTestResult(mContext, testResult));
+    }
+
+    @Override
+    public void addTest(Test test) {
+        mWrappedTestSuite.addTest(test);
+    }
+
+    @Override
+    public int countTestCases() {
+        return mWrappedTestSuite.countTestCases();
+    }
+
+    @Override
+    public String getName() {
+        return mWrappedTestSuite.getName();
+    }
+
+    @Override
+    public void runTest(Test test, TestResult testResult) {
+        mWrappedTestSuite.runTest(test, testResult);
+    }
+
+    @Override
+    public void setName(String name) {
+        mWrappedTestSuite.setName(name);
+    }
+
+    @Override
+    public Test testAt(int index) {
+        return mWrappedTestSuite.testAt(index);
+    }
+
+    @Override
+    public int testCount() {
+        return mWrappedTestSuite.testCount();
+    }
+
+    @Override
+    public Enumeration<Test> tests() {
+        return mWrappedTestSuite.tests();
+    }
+
+    @Override
+    public String toString() {
+        return mWrappedTestSuite.toString();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/base/IGnssTestStateContainer.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/IGnssTestStateContainer.java
new file mode 100644
index 0000000..498c599
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/base/IGnssTestStateContainer.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.verifier.location.base;
+
+import android.content.ContentResolver;
+import android.content.Intent;
+
+/**
+ * An interface that defines a facade for {@link BaseGnssTestActivity}, so it can be consumed by
+ * other CtsVerifier Sensor Test Framework helper components.
+ */
+public interface IGnssTestStateContainer {
+
+    /**
+     * Waits for the operator to acknowledge to continue execution.
+     */
+    void waitForUserToContinue() throws InterruptedException;
+
+    /**
+     * @param resId The resource Id to extract.
+     * @return The extracted string.
+     */
+    String getString(int resId);
+
+    /**
+     * @param resId  The resource Id to extract.
+     * @param params The parameters to format the string represented by the resource contents.
+     * @return The formatted extracted string.
+     */
+    String getString(int resId, Object... params);
+
+    /**
+     * Starts an Activity and blocks until it completes, then it returns its result back to the
+     * client.
+     *
+     * @param action The action to start the Activity.
+     * @return The Activity's result code.
+     */
+    int executeActivity(String action) throws InterruptedException;
+
+    /**
+     * Starts an Activity and blocks until it completes, then it returns its result back to the
+     * client.
+     *
+     * @param intent The intent to start the Activity.
+     * @return The Activity's result code.
+     */
+    int executeActivity(Intent intent) throws InterruptedException;
+
+    /**
+     * @return The {@link ContentResolver} associated with the test.
+     */
+    ContentResolver getContentResolver();
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/reporting/GnssTestDetails.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/reporting/GnssTestDetails.java
new file mode 100644
index 0000000..ea04123
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/reporting/GnssTestDetails.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.cts.verifier.location.reporting;
+
+import com.android.cts.verifier.R;
+
+import org.junit.runner.Result;
+
+import android.content.Context;
+
+/**
+ * A class that holds the result of a Gnss test execution.
+ */
+public class GnssTestDetails {
+    private final String mName;
+    private final ResultCode mResultCode;
+    private final String mSummary;
+
+    public enum ResultCode {
+        SKIPPED,
+        PASS,
+        FAIL,
+        INTERRUPTED
+    }
+
+    public GnssTestDetails(String name, ResultCode resultCode) {
+        this(name, resultCode, null /* summary */);
+    }
+
+    public GnssTestDetails(String name, ResultCode resultCode, String summary) {
+        mName = name;
+        mResultCode = resultCode;
+        mSummary = summary;
+    }
+
+    public GnssTestDetails(
+            Context context,
+            String name,
+            int passCount,
+            int skipCount,
+            int failCount) {
+        ResultCode resultCode = ResultCode.PASS;
+        if (failCount > 0) {
+            resultCode = ResultCode.FAIL;
+        } else if (skipCount > 0) {
+            resultCode = ResultCode.SKIPPED;
+        }
+
+        mName = name;
+        mResultCode = resultCode;
+        mSummary = context.getString(R.string.snsr_test_summary, passCount, skipCount, failCount);
+    }
+
+    public GnssTestDetails(Context context, String name, Result result) {
+        this(context,
+                name,
+                result.getRunCount() - result.getFailureCount() - result.getIgnoreCount(),
+                result.getIgnoreCount(),
+                result.getFailureCount());
+    }
+
+    public GnssTestDetails(String name, String tag, Throwable cause) {
+        ResultCode resultCode = ResultCode.FAIL;
+        if (cause instanceof InterruptedException) {
+            resultCode = ResultCode.INTERRUPTED;
+            // the interrupted status must be restored, so other routines can consume it
+            Thread.currentThread().interrupt();
+        }
+        mName = name;
+        mResultCode = resultCode;
+        mSummary = String.format("[%s] %s", tag, cause.getMessage());
+    }
+
+    public String getName() {
+        return mName;
+    }
+
+    public ResultCode getResultCode() {
+        return mResultCode;
+    }
+
+    public String getSummary() {
+        return mSummary;
+    }
+
+    public GnssTestDetails cloneAndChangeResultCode(ResultCode resultCode) {
+        return new GnssTestDetails(mName, resultCode, mSummary);
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s|%s|%s", mName, mResultCode.name(), mSummary);
+    }
+}
+
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
index 4f26b9c..4e39720 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
@@ -21,6 +21,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.BitmapFactory;
 import android.os.Bundle;
 import android.os.UserManager;
 import android.util.Log;
@@ -55,6 +56,7 @@
     public static final String COMMAND_PROFILE_OWNER_CLEAR_POLICIES = "po-clear-policies";
     public static final String COMMAND_REMOVE_DEVICE_OWNER = "remove-device-owner";
     public static final String COMMAND_REQUEST_BUGREPORT = "request-bugreport";
+    public static final String COMMAND_SET_USER_ICON = "set-user-icon";
 
     public static final String EXTRA_USER_RESTRICTION =
             "com.android.cts.verifier.managedprovisioning.extra.USER_RESTRICTION";
@@ -161,6 +163,13 @@
                     }
                     clearProfileOwnerRelatedPolicies();
                 } break;
+                case COMMAND_SET_USER_ICON: {
+                    if (!mDpm.isDeviceOwnerApp(getPackageName())) {
+                        return;
+                    }
+                    mDpm.setUserIcon(mAdmin, BitmapFactory.decodeResource(getResources(),
+                            com.android.cts.verifier.R.drawable.icon));
+                } break;
             }
         } catch (Exception e) {
             Log.e(TAG, "Failed to execute command: " + intent, e);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
index 8e0dcb6..163f2fe 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
@@ -66,6 +66,7 @@
     private static final String DISALLOW_CONFIG_WIFI_ID = "DISALLOW_CONFIG_WIFI";
     private static final String DISALLOW_CONFIG_VPN_ID = "DISALLOW_CONFIG_VPN";
     private static final String DISALLOW_USB_FILE_TRANSFER_ID = "DISALLOW_USB_FILE_TRANSFER";
+    private static final String SET_USER_ICON_TEST_ID = "SET_USER_ICON";
     private static final String DISALLOW_DATA_ROAMING_ID = "DISALLOW_DATA_ROAMING";
     private static final String POLICY_TRANSPARENCY_TEST_ID = "POLICY_TRANSPARENCY";
     private static final String REMOVE_DEVICE_OWNER_TEST_ID = "REMOVE_DEVICE_OWNER";
@@ -256,6 +257,17 @@
                                         CommandReceiverActivity.COMMAND_SET_KEYGUARD_DISABLED,
                                                 false))}));
 
+        adapter.add(createInteractiveTestItem(this, SET_USER_ICON_TEST_ID,
+                R.string.device_owner_set_user_icon,
+                R.string.device_owner_set_user_icon_instruction,
+                new ButtonInfo[] {
+                        new ButtonInfo(
+                                R.string.device_owner_set_user_icon_button,
+                                createSetUserIconIntent()),
+                        new ButtonInfo(
+                                R.string.device_owner_settings_go,
+                                new Intent(Settings.ACTION_SETTINGS))}));
+
         // setPermissionGrantState
         adapter.add(createTestItem(this, CHECK_PERMISSION_LOCKDOWN_TEST_ID,
                 R.string.device_profile_owner_permission_lockdown_test,
@@ -307,4 +319,10 @@
                 .putExtra(CommandReceiverActivity.EXTRA_USER_RESTRICTION, restriction)
                 .putExtra(CommandReceiverActivity.EXTRA_ENFORCED, true);
     }
+
+    private Intent createSetUserIconIntent() {
+        return new Intent(this, CommandReceiverActivity.class)
+                .putExtra(CommandReceiverActivity.EXTRA_COMMAND,
+                        CommandReceiverActivity.COMMAND_SET_USER_ICON);
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
index e8e2cee..56c8ac0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.media.tv.TvContract;
+import android.media.tv.TvInputManager;
 import android.os.AsyncTask;
 import android.view.View;
 
@@ -36,6 +37,8 @@
             TvContract.Channels.CONTENT_URI);
     private static final Intent EPG_INTENT = new Intent(Intent.ACTION_VIEW,
             TvContract.Programs.CONTENT_URI);
+    private static final Intent TV_TRIGGER_SETUP_INTENT = new Intent(
+            TvInputManager.ACTION_SETUP_INPUTS);
 
     private static final long TIMEOUT_MS = 5l * 60l * 1000l;  // 5 mins.
 
@@ -47,6 +50,8 @@
     private View mVerifyGlobalSearchItem;
     private View mGoToEpgItem;
     private View mVerifyEpgItem;
+    private View mTriggerSetupItem;
+    private View mVerifyTriggerSetupItem;
     private boolean mTuneVerified;
     private boolean mOverlayViewVerified;
     private boolean mGlobalSearchVerified;
@@ -109,6 +114,13 @@
             setButtonEnabled(mVerifyEpgItem, true);
         } else if (containsButton(mVerifyEpgItem, v)) {
             setPassState(mVerifyEpgItem, true);
+            setButtonEnabled(mTriggerSetupItem, true);
+        } else if (containsButton(mTriggerSetupItem, v)) {
+            startActivity(TV_TRIGGER_SETUP_INTENT);
+            setPassState(mTriggerSetupItem, true);
+            setButtonEnabled(mVerifyTriggerSetupItem, true);
+        } else if (containsButton(mVerifyTriggerSetupItem, v)) {
+            setPassState(mVerifyTriggerSetupItem, true);
             getPassButton().setEnabled(true);
         }
     }
@@ -130,6 +142,10 @@
                 R.string.tv_launch_epg, this);
         mVerifyEpgItem = createUserItem(R.string.tv_input_discover_test_verify_epg,
                 android.R.string.yes, this);
+        mTriggerSetupItem = createUserItem(R.string.tv_input_discover_test_trigger_setup,
+                R.string.tv_launch_setup, this);
+        mVerifyTriggerSetupItem = createUserItem(
+                R.string.tv_input_discover_test_verify_trigger_setup, android.R.string.yes, this);
     }
 
     @Override
diff --git a/build/device_info_package.mk b/build/device_info_package.mk
index 0ccb05d..b91c264 100644
--- a/build/device_info_package.mk
+++ b/build/device_info_package.mk
@@ -20,7 +20,6 @@
 DEVICE_INFO_INSTRUMENT := android.support.test.runner.AndroidJUnitRunner
 DEVICE_INFO_PERMISSIONS += android.permission.WRITE_EXTERNAL_STORAGE
 DEVICE_INFO_ACTIVITIES += \
-  $(DEVICE_INFO_PACKAGE).CameraDeviceInfo \
   $(DEVICE_INFO_PACKAGE).ConfigurationDeviceInfo \
   $(DEVICE_INFO_PACKAGE).CpuDeviceInfo \
   $(DEVICE_INFO_PACKAGE).FeatureDeviceInfo \
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java b/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java
index 57b9e3e..cb81d0b 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/DeviceReportLog.java
@@ -37,7 +37,8 @@
 public class DeviceReportLog extends ReportLog {
     private static final String TAG = DeviceReportLog.class.getSimpleName();
     private static final String RESULT = "COMPATIBILITY_TEST_RESULT";
-    private static final String DEFAULT_REPORT_LOG_NAME = "DefaultTestMetrics";
+    // TODO(mishragaurav): Remove default names and constructor after fixing b/27950009.
+    private static final String DEFAULT_REPORT_LOG_NAME = "DefaultDeviceTestMetrics";
     private static final String DEFAULT_STREAM_NAME = "DefaultStream";
     private static final int INST_STATUS_ERROR = -1;
     private static final int INST_STATUS_IN_PROGRESS = 2;
@@ -72,7 +73,7 @@
 
     @Override
     public void addValue(String source, String message, double value, ResultType type,
-             ResultUnit unit) {
+            ResultUnit unit) {
         super.addValue(source, message, value, type, unit);
         try {
             store.addResult(message, value);
@@ -82,8 +83,7 @@
     }
 
     @Override
-    public void addValue(String message, double value, ResultType type,
-                         ResultUnit unit) {
+    public void addValue(String message, double value, ResultType type, ResultUnit unit) {
         super.addValue(message, value, type, unit);
         try {
             store.addResult(message, value);
@@ -94,7 +94,7 @@
 
     @Override
     public void addValues(String source, String message, double[] values, ResultType type,
-                         ResultUnit unit) {
+            ResultUnit unit) {
         super.addValues(source, message, values, type, unit);
         try {
             store.addArrayResult(message, values);
@@ -104,8 +104,7 @@
     }
 
     @Override
-    public void addValues(String message, double[] values, ResultType type,
-                         ResultUnit unit) {
+    public void addValues(String message, double[] values, ResultType type, ResultUnit unit) {
         super.addValues(message, values, type, unit);
         try {
             store.addArrayResult(message, values);
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/ReportLogDeviceInfoStore.java b/common/device-side/util/src/com/android/compatibility/common/util/ReportLogDeviceInfoStore.java
index 67e6c39..fd61b08 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/ReportLogDeviceInfoStore.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/ReportLogDeviceInfoStore.java
@@ -57,8 +57,8 @@
         }
         mJsonFile.createNewFile();
         formatWriter = new BufferedWriter(new FileWriter(mJsonFile));
-        formatWriter.write(oldMetrics + "\"" + mStreamName + "\":", 0,
-            oldMetrics.length() + mStreamName.length() + 3);
+        formatWriter.write(oldMetrics + "\"" + mStreamName + "\":", 0, oldMetrics.length() +
+                mStreamName.length() + 3);
         formatWriter.flush();
         formatWriter.close();
         mJsonWriter = new JsonWriter(new FileWriter(mJsonFile, true));
diff --git a/common/device-side/util/tests/src/com/android/compatibility/common/util/DeviceReportTest.java b/common/device-side/util/tests/src/com/android/compatibility/common/util/DeviceReportTest.java
index b8887cf..25fb4d7 100644
--- a/common/device-side/util/tests/src/com/android/compatibility/common/util/DeviceReportTest.java
+++ b/common/device-side/util/tests/src/com/android/compatibility/common/util/DeviceReportTest.java
@@ -88,10 +88,10 @@
     }
 
     public void testFile() throws Exception {
-        final File dir = new File(Environment.getExternalStorageDirectory(), "report-log-files");
         assertTrue("External storage is not mounted",
                 Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED));
-        assertTrue("Report Log directory missing", dir.isDirectory());
+        final File dir = new File(Environment.getExternalStorageDirectory(), "report-log-files");
+        assertTrue("Report Log directory missing", dir.isDirectory() || dir.mkdirs());
 
         // Remove files from earlier possible runs.
         File[] files = dir.listFiles();
diff --git a/common/host-side/tradefed/res/report/compatibility_result.xsl b/common/host-side/tradefed/res/report/compatibility_result.xsl
index 1fb4e83..ac5c282 100644
--- a/common/host-side/tradefed/res/report/compatibility_result.xsl
+++ b/common/host-side/tradefed/res/report/compatibility_result.xsl
@@ -16,6 +16,7 @@
 
 <!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#160;"> ]>
 <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
     <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
 
     <xsl:template match="/">
@@ -31,69 +32,41 @@
                 <div>
                     <table class="title">
                         <tr>
-                            <td width="40%" align="left"><img src="logo.png"></img></td>
-                            <td width="60%" align="left">
-                                <h1>Test Report</h1>
-                            </td>
+                            <td align="left"><img src="logo.png"/></td>
                         </tr>
                     </table>
                 </div>
-                <img src="newrule_green.png" align="left"></img>
-
-                <br></br>
-
-                <center>
-                    <a href="device-info/GenericDeviceInfo.deviceinfo.json" >Device Information</a>
-                </center>
-
-                <br></br>
 
                 <div>
                     <table class="summary">
                         <tr>
-                            <th colspan="2">Test Summary</th>
+                            <th colspan="2">Summary</th>
                         </tr>
                         <tr>
-                            <td class="rowtitle">Compatibility Suite</td>
+                            <td class="rowtitle">Suite / Plan</td>
                             <td>
-                                <xsl:value-of select="Result/@suite_name"/>
+                                <xsl:value-of select="Result/@suite_name"/> / <xsl:value-of select="Result/@plan"/>
                             </td>
                         </tr>
                         <tr>
-                            <td class="rowtitle">Compatibility Version</td>
+                            <td class="rowtitle">Suite / Build</td>
                             <td>
-                                <xsl:value-of select="Result/@suite_version"/>
-                            </td>
-                        </tr>
-                        <tr>
-                            <td class="rowtitle">Report Version</td>
-                            <td>
-                                <xsl:value-of select="Result/@report_version"/>
+                                <xsl:value-of select="Result/@suite_version"/> / <xsl:value-of select="Result/@suite_build_number"/>
                             </td>
                         </tr>
                         <tr>
                             <td class="rowtitle">Host Info</td>
                             <td>
+                                Result/@start
                                 <xsl:value-of select="Result/@host_name"/>
                                 (<xsl:value-of select="Result/@os_name"/> - <xsl:value-of select="Result/@os_version"/>)
                             </td>
                         </tr>
                         <tr>
-                            <td class="rowtitle">Plan</td>
+                            <td class="rowtitle">Start time / End Time</td>
                             <td>
-                                <xsl:value-of select="Result/@plan"/>
-                            </td>
-                        </tr>
-                        <tr>
-                            <td class="rowtitle">Start time</td>
-                            <td>
-                                <xsl:value-of select="Result/@start"/>
-                            </td>
-                        </tr>
-                        <tr>
-                            <td class="rowtitle">End time</td>
-                            <td>
-                                <xsl:value-of select="Result/@end"/>
+                                <xsl:value-of select="Result/@start_display"/> /
+                                <xsl:value-of select="Result/@end_display"/>
                             </td>
                         </tr>
                         <tr>
@@ -114,11 +87,35 @@
                                 <xsl:value-of select="Result/Summary/@not_executed"/>
                             </td>
                         </tr>
+                        <tr>
+                            <td class="rowtitle">Fingerprint</td>
+                            <td>
+                                <xsl:value-of select="Result/Build/@build_fingerprint"/>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class="rowtitle">Security Patch</td>
+                            <td>
+                                <xsl:value-of select="Result/Build/@build_version_security_patch"/>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class="rowtitle">Release (SDK)</td>
+                            <td>
+                                <xsl:value-of select="Result/Build/@build_version_release"/> (<xsl:value-of select="Result/Build/@build_version_sdk"/>)
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class="rowtitle">ABIs</td>
+                            <td>
+                                <xsl:value-of select="Result/Build/@build_abis"/>
+                            </td>
+                        </tr>
                     </table>
                 </div>
 
                 <!-- High level summary of test execution -->
-                <h2 align="center">Test Summary by Module</h2>
+                <br/>
                 <div>
                     <table class="testsummary">
                         <tr>
@@ -135,16 +132,16 @@
                                     <a href="#{$href}"><xsl:value-of select="@name"/> - <xsl:value-of select="@abi"/></a>
                                 </td>
                                 <td>
-                                    <xsl:value-of select="count(Test[@result = 'pass'])"/>
+                                    <xsl:value-of select="count(TestCase/Test[@result = 'pass'])"/>
                                 </td>
                                 <td>
-                                    <xsl:value-of select="count(Test[@result = 'fail'])"/>
+                                    <xsl:value-of select="count(TestCase/Test[@result = 'fail'])"/>
                                 </td>
                                 <td>
-                                    <xsl:value-of select="count(Test[@result = 'not_executed'])"/>
+                                    <xsl:value-of select="count(TestCase/Test[@result = 'not_executed'])"/>
                                 </td>
                                 <td>
-                                    <xsl:value-of select="count(Test)"/>
+                                    <xsl:value-of select="count(TestCase/Test)"/>
                                 </td>
                             </tr>
                         </xsl:for-each> <!-- end Module -->
@@ -161,7 +158,7 @@
                     <xsl:with-param name="resultFilter" select="'not_executed'" />
                 </xsl:call-template>
 
-                <h2 align="center">Detailed Test Report</h2>
+                <br/>
                 <xsl:call-template name="detailedTestReport" />
 
             </body>
@@ -201,46 +198,49 @@
                             <th>Details</th>
                         </tr>
 
-                        <!-- test -->
-                        <xsl:for-each select="Test">
-                            <xsl:if test="$resultFilter='' or $resultFilter=@result">
-                                <tr>
-                                    <td class="testname"> -- <xsl:value-of select="@name"/></td>
+                        <xsl:for-each select="TestCase">
+                            <xsl:variable name="TestCase" select="."/>
+                            <!-- test -->
+                            <xsl:for-each select="Test">
+                                <xsl:if test="$resultFilter='' or $resultFilter=@result">
+                                    <tr>
+                                        <td class="testname"> <xsl:value-of select="$TestCase/@name"/>#<xsl:value-of select="@name"/></td>
 
-                                    <!-- test results -->
-                                    <xsl:if test="@result='pass'">
-                                        <td class="pass">
-                                            <div style="text-align: center; margin-left:auto; margin-right:auto;">
-                                                <xsl:value-of select="@result"/>
-                                            </div>
-                                        </td>
-                                        <td class="failuredetails"/>
-                                    </xsl:if>
+                                        <!-- test results -->
+                                        <xsl:if test="@result='pass'">
+                                            <td class="pass">
+                                                <div style="text-align: center; margin-left:auto; margin-right:auto;">
+                                                    <xsl:value-of select="@result"/>
+                                                </div>
+                                            </td>
+                                            <td class="failuredetails"/>
+                                        </xsl:if>
 
-                                    <xsl:if test="@result='fail'">
-                                        <td class="failed">
-                                            <div style="text-align: center; margin-left:auto; margin-right:auto;">
-                                                <xsl:value-of select="@result"/>
-                                            </div>
-                                        </td>
-                                        <td class="failuredetails">
-                                            <div class="details">
-                                                <xsl:value-of select="Failure/@message"/>
-                                            </div>
-                                        </td>
-                                    </xsl:if>
+                                        <xsl:if test="@result='fail'">
+                                            <td class="failed">
+                                                <div style="text-align: center; margin-left:auto; margin-right:auto;">
+                                                    <xsl:value-of select="@result"/>
+                                                </div>
+                                            </td>
+                                            <td class="failuredetails">
+                                                <div class="details">
+                                                    <xsl:value-of select="Failure/@message"/>
+                                                </div>
+                                            </td>
+                                        </xsl:if>
 
-                                    <xsl:if test="@result='not_executed'">
-                                        <td class="not_executed">
-                                            <div style="text-align: center; margin-left:auto; margin-right:auto;">
-                                                <xsl:value-of select="@result"/>
-                                            </div>
-                                        </td>
-                                        <td class="failuredetails"></td>
-                                    </xsl:if>
-                                </tr> <!-- finished with a row -->
-                            </xsl:if>
-                        </xsl:for-each> <!-- end test -->
+                                        <xsl:if test="@result='not_executed'">
+                                            <td class="not_executed">
+                                                <div style="text-align: center; margin-left:auto; margin-right:auto;">
+                                                    <xsl:value-of select="@result"/>
+                                                </div>
+                                            </td>
+                                            <td class="failuredetails"></td>
+                                        </xsl:if>
+                                    </tr> <!-- finished with a row -->
+                                </xsl:if>
+                            </xsl:for-each> <!-- end test -->
+                        </xsl:for-each>
                     </table>
                 </xsl:if>
             </xsl:for-each> <!-- end test Module -->
diff --git a/common/host-side/tradefed/res/report/newrule_green.png b/common/host-side/tradefed/res/report/newrule_green.png
deleted file mode 100644
index 10a4194..0000000
--- a/common/host-side/tradefed/res/report/newrule_green.png
+++ /dev/null
Binary files differ
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
index 14f3812..9f9728b 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
@@ -75,8 +75,7 @@
         "compatibility_result.css",
         "compatibility_result.xsd",
         "compatibility_result.xsl",
-        "logo.png",
-        "newrule_green.png"};
+        "logo.png"};
 
     @Option(name = CompatibilityTest.RETRY_OPTION,
             shortName = 'r',
@@ -196,7 +195,7 @@
     @Override
     public void testStarted(TestIdentifier test) {
         mCurrentCaseResult = mCurrentModuleResult.getOrCreateResult(test.getClassName());
-        mCurrentResult = mCurrentCaseResult.getOrCreateResult(test.getTestName());
+        mCurrentResult = mCurrentCaseResult.getOrCreateResult(test.getTestName().trim());
         mCurrentResult.reset();
     }
 
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ReportLogCollector.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ReportLogCollector.java
index c786ef4..1ee7dd3 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ReportLogCollector.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ReportLogCollector.java
@@ -25,6 +25,7 @@
 import com.android.tradefed.targetprep.BuildError;
 import com.android.tradefed.targetprep.ITargetCleaner;
 import com.android.tradefed.targetprep.TargetSetupError;
+import com.android.tradefed.util.FileUtil;
 
 import java.io.BufferedWriter;
 import java.io.File;
@@ -43,6 +44,9 @@
     @Option(name = "dest-dir", description = "The directory under the result to store the files")
     private String mDestDir;
 
+    @Option(name = "temp-dir", description = "The temp directory containing host-side report logs")
+    private String mTempReportFolder;
+
     public ReportLogCollector() {
     }
 
@@ -79,19 +83,47 @@
         CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
         try {
             File resultDir = buildHelper.getResultDir();
+            if (mDestDir != null) {
+                resultDir = new File(resultDir, mDestDir);
+            }
+            resultDir.mkdirs();
+            if (!resultDir.isDirectory()) {
+                CLog.e("%s is not a directory", resultDir.getAbsolutePath());
+                return;
+            }
             String resultPath = resultDir.getAbsolutePath();
-            pull(device, mSrcDir, resultPath);
-        } catch (FileNotFoundException fnfe) {
-            fnfe.printStackTrace();
+            final File hostReportDir = FileUtil.createNamedTempDir(mTempReportFolder);
+            if (!hostReportDir.isDirectory()) {
+                CLog.e("%s is not a directory", hostReportDir.getAbsolutePath());
+                return;
+            }
+            String hostReportsPath = hostReportDir.getAbsolutePath();
+            pull(device, mSrcDir, hostReportsPath, resultPath);
+        } catch (Exception exception) {
+            exception.printStackTrace();
         }
     }
 
-    private void pull(ITestDevice device, String src, String dest) {
-        String command = String.format("adb -s %s pull %s %s", device.getSerialNumber(), src, dest);
+    private void pull(ITestDevice device, String deviceSrc, String hostSrc, String dest) {
+        String deviceSideCommand = String.format("adb -s %s pull %s %s", device.getSerialNumber(),
+                deviceSrc, dest);
+        String hostSideCommand = String.format("cp -r %s/* %s", hostSrc, dest);
+        String cleanUpCommand = String.format("rm -rf %s", hostSrc);
         try {
-            Process p = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", command});
-            if (p.waitFor() != 0) {
-                CLog.e("Failed to run %s", command);
+            Process deviceProcess = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c",
+                    deviceSideCommand});
+            if (deviceProcess.waitFor() != 0) {
+                CLog.v("No device-side report logs pulled.");
+            }
+            Process hostProcess = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c",
+                    hostSideCommand});
+            if (hostProcess.waitFor() != 0) {
+                CLog.v("No host-side report logs pulled");
+            }
+            Process cleanUpProcess = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c",
+                    cleanUpCommand});
+            if (cleanUpProcess.waitFor() != 0) {
+                CLog.e("Failed to run %s", cleanUpCommand);
             }
         } catch (Exception e) {
             CLog.e("Caught exception during pull.");
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
index 639ec88..50d1de1 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
@@ -76,11 +76,6 @@
     public static final String DEVICE_TOKEN_OPTION = "device-token";
     private static final String URL = "dynamic-config-url";
 
-    private static final TestStatus[] RETRY_TEST_STATUS = new TestStatus[] {
-            TestStatus.FAIL,
-            TestStatus.NOT_EXECUTED
-    };
-
     @Option(name = PLAN_OPTION,
             description = "the test suite plan to run, such as \"everything\" or \"cts\"",
             importance = Importance.ALWAYS)
@@ -347,21 +342,15 @@
             }
             // Append each test that failed or was not executed to the filters
             for (IModuleResult module : result.getModules()) {
-                for (ICaseResult cr : module.getResults()) {
-                    for (TestStatus status : RETRY_TEST_STATUS) {
-                        for (ITestResult r : cr.getResults(status)) {
-                            // Create the filter for the test to be run.
-                            TestFilter filter = new TestFilter(
-                                    module.getAbi(), module.getName(), r.getFullName());
-                            mIncludeFilters.add(filter.toString());
-                        }
+                for (ICaseResult testResultList : module.getResults()) {
+                    for (ITestResult testResult : testResultList.getResults(TestStatus.PASS)) {
+                        // Create the filter for the test to be run.
+                        TestFilter filter = new TestFilter(
+                                module.getAbi(), module.getName(), testResult.getFullName());
+                        mExcludeFilters.add(filter.toString());
                     }
                 }
             }
-            if (mIncludeFilters.isEmpty()) {
-                throw new IllegalArgumentException(String.format(
-                        "No tests to retry in session %d", mRetrySessionId));
-            }
         } else if (mModuleName != null) {
             mIncludeFilters.clear();
             try {
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java
index 3fcf8b5..6228cd7 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java
@@ -62,8 +62,7 @@
         "compatibility_result.css",
         "compatibility_result.xsd",
         "compatibility_result.xsl",
-        "logo.png",
-        "newrule_green.png"};
+        "logo.png"};
 
     private ResultReporter mReporter;
     private IBuildInfo mBuildInfo;
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/HostInfoStore.java b/common/host-side/util/src/com/android/compatibility/common/util/HostInfoStore.java
index 4a3613d..a17f17a 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/HostInfoStore.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/HostInfoStore.java
@@ -27,8 +27,12 @@
 
 public class HostInfoStore extends InfoStore {
 
-    private final File mJsonFile;
-    private JsonWriter mJsonWriter = null;
+    protected File mJsonFile;
+    protected JsonWriter mJsonWriter = null;
+
+    public HostInfoStore() {
+        mJsonFile = null;
+    }
 
     public HostInfoStore(File file) throws Exception {
         mJsonFile = file;
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/MetricsReportLog.java b/common/host-side/util/src/com/android/compatibility/common/util/MetricsReportLog.java
index 4675231..e590b91 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/MetricsReportLog.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/MetricsReportLog.java
@@ -16,6 +16,11 @@
 
 package com.android.compatibility.common.util;
 
+import com.android.tradefed.util.FileUtil;
+
+import java.io.File;
+import java.io.IOException;
+
 /**
  * A {@link ReportLog} that can be used with the in memory metrics store used for host side metrics.
  */
@@ -24,6 +29,14 @@
     private final String mAbi;
     private final String mClassMethodName;
 
+    // TODO(mishragaurav): Remove default names and constructor after fixing b/27950009.
+    private static final String DEFAULT_REPORT_LOG_NAME = "DefaultHostTestMetrics";
+    private static final String DEFAULT_STREAM_NAME = "DefaultStream";
+    // Temporary folder must match the temp-dir value configured in ReportLogCollector target
+    // preparer in cts/tools/cts-tradefed/res/config/cts-oreconditions.xml
+    private static final String TEMPORARY_REPORT_FOLDER = "temp-report-logs/";
+    private ReportLogHostInfoStore store;
+
     /**
      * @param deviceSerial serial number of the device
      * @param abi abi the test was run on
@@ -31,12 +44,58 @@
      *        Note that ReportLog.getClassMethodNames() provide this.
      */
     public MetricsReportLog(String deviceSerial, String abi, String classMethodName) {
+        this(deviceSerial, abi, classMethodName, DEFAULT_REPORT_LOG_NAME, DEFAULT_STREAM_NAME);
+    }
+
+    public MetricsReportLog(String deviceSerial, String abi, String classMethodName,
+            String reportLogName) {
+        this(deviceSerial, abi, classMethodName, reportLogName, DEFAULT_STREAM_NAME);
+    }
+
+    public MetricsReportLog(String deviceSerial, String abi, String classMethodName,
+            String reportLogName, String streamName) {
+        super(reportLogName, streamName);
         mDeviceSerial = deviceSerial;
         mAbi = abi;
         mClassMethodName = classMethodName;
+        try {
+            final File dir = FileUtil.createNamedTempDir(TEMPORARY_REPORT_FOLDER);
+            File jsonFile = new File(dir, mReportLogName + ".reportlog.json");
+            store = new ReportLogHostInfoStore(jsonFile, mStreamName);
+            store.open();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void addValue(String source, String message, double value, ResultType type,
+            ResultUnit unit) {
+        super.addValue(source, message, value, type, unit);
+        try {
+            store.addResult(message, value);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void addValue(String message, double value, ResultType type, ResultUnit unit) {
+        super.addValue(message, value, type, unit);
+        try {
+            store.addResult(message, value);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
     }
 
     public void submit() {
+        try {
+            store.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
         MetricsStore.storeResult(mDeviceSerial, mAbi, mClassMethodName, this);
     }
 }
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/ReportLogHostInfoStore.java b/common/host-side/util/src/com/android/compatibility/common/util/ReportLogHostInfoStore.java
new file mode 100644
index 0000000..65114d9
--- /dev/null
+++ b/common/host-side/util/src/com/android/compatibility/common/util/ReportLogHostInfoStore.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.util;
+
+import com.android.json.stream.JsonWriter;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+
+public class ReportLogHostInfoStore extends HostInfoStore {
+
+    private final String mStreamName;
+
+    public ReportLogHostInfoStore(File jsonFile, String streamName) throws Exception {
+        mJsonFile = jsonFile;
+        mStreamName = streamName;
+    }
+
+    /**
+     * Creates the writer and starts the JSON Object for the metric stream.
+     */
+    @Override
+    public void open() throws IOException {
+        BufferedWriter formatWriter;
+        String oldMetrics;
+        if (mJsonFile.exists()) {
+            BufferedReader jsonReader = new BufferedReader(new FileReader(mJsonFile));
+            StringBuilder oldMetricsBuilder = new StringBuilder();
+            String line;
+            while ((line = jsonReader.readLine()) != null) {
+                oldMetricsBuilder.append(line);
+            }
+            oldMetrics = oldMetricsBuilder.toString().trim();
+            if (oldMetrics.charAt(oldMetrics.length() - 1) == '}') {
+                oldMetrics = oldMetrics.substring(0, oldMetrics.length() - 1);
+            }
+            oldMetrics = oldMetrics + ",";
+        } else {
+            oldMetrics = "{";
+        }
+        mJsonFile.createNewFile();
+        formatWriter = new BufferedWriter(new FileWriter(mJsonFile));
+        formatWriter.write(oldMetrics + "\"" + mStreamName + "\":", 0, oldMetrics.length() +
+                mStreamName.length() + 3);
+        formatWriter.flush();
+        formatWriter.close();
+        mJsonWriter = new JsonWriter(new FileWriter(mJsonFile, true));
+        mJsonWriter.beginObject();
+    }
+
+    /**
+     * Closes the writer.
+     */
+    @Override
+    public void close() throws IOException {
+        mJsonWriter.endObject();
+        mJsonWriter.close();
+        // Close the overall JSON object
+        BufferedWriter formatWriter = new BufferedWriter(new FileWriter(mJsonFile, true));
+        formatWriter.write("}", 0, 1);
+        formatWriter.flush();
+        formatWriter.close();
+    }
+}
diff --git a/common/util/src/com/android/compatibility/common/util/ResultHandler.java b/common/util/src/com/android/compatibility/common/util/ResultHandler.java
index 5f05229..d91763c 100644
--- a/common/util/src/com/android/compatibility/common/util/ResultHandler.java
+++ b/common/util/src/com/android/compatibility/common/util/ResultHandler.java
@@ -28,7 +28,9 @@
 import java.io.OutputStream;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 import java.util.Map.Entry;
 import java.util.Set;
@@ -50,6 +52,7 @@
     private static final String BUILD_TAG = "Build";
     private static final String CASE_TAG = "TestCase";
     private static final String DEVICES_ATTR = "devices";
+    private static final String END_DISPLAY_TIME_ATTR = "end_display";
     private static final String END_TIME_ATTR = "end";
     private static final String FAILED_ATTR = "failed";
     private static final String FAILURE_TAG = "Failure";
@@ -72,6 +75,7 @@
     private static final String RUNTIME_ATTR = "runtime";
     private static final String SCREENSHOT_TAG = "Screenshot";
     private static final String STACK_TAG = "StackTrace";
+    private static final String START_DISPLAY_TIME_ATTR = "start_display";
     private static final String START_TIME_ATTR = "start";
     private static final String SUITE_NAME_ATTR = "suite_name";
     private static final String SUITE_PLAN_ATTR = "suite_plan";
@@ -205,10 +209,13 @@
         serializer.startDocument(ENCODING, false);
         serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
         serializer.processingInstruction(
-                "xml-stylesheet type=\"text/xsl\" href=\"compatibility-result.xsl\"");
+                "xml-stylesheet type=\"text/xsl\" href=\"compatibility_result.xsl\"");
         serializer.startTag(NS, RESULT_TAG);
         serializer.attribute(NS, START_TIME_ATTR, String.valueOf(startTime));
         serializer.attribute(NS, END_TIME_ATTR, String.valueOf(endTime));
+        serializer.attribute(NS, START_DISPLAY_TIME_ATTR, toReadableDateString(startTime));
+        serializer.attribute(NS, END_DISPLAY_TIME_ATTR, toReadableDateString(endTime));
+
         serializer.attribute(NS, SUITE_NAME_ATTR, suiteName);
         serializer.attribute(NS, SUITE_VERSION_ATTR, suiteVersion);
         serializer.attribute(NS, SUITE_PLAN_ATTR, suitePlan);
@@ -315,4 +322,15 @@
         return resultFile;
     }
 
+    /**
+     * Return the given time as a {@link String} suitable for displaying.
+     * <p/>
+     * Example: Fri Aug 20 15:13:03 PDT 2010
+     *
+     * @param time the epoch time in ms since midnight Jan 1, 1970
+     */
+    static String toReadableDateString(long time) {
+        SimpleDateFormat dateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
+        return dateFormat.format(new Date(time));
+    }
 }
diff --git a/common/util/src/com/android/compatibility/common/util/TestFilter.java b/common/util/src/com/android/compatibility/common/util/TestFilter.java
index 78b68cfc..47ed9ec 100644
--- a/common/util/src/com/android/compatibility/common/util/TestFilter.java
+++ b/common/util/src/com/android/compatibility/common/util/TestFilter.java
@@ -27,15 +27,20 @@
     /**
      * Builds a new {@link TestFilter} from the given string. Filters can be in one of four forms,
      * the instance will be initialized as;
-     * -"name"              -> abi = null, name = "name", test = null
-     * -"name" "test"       -> abi = null, name = "name", test = "test"
-     * -"abi" "name"        -> abi = "abi", name = "name", test = null
-     * -"abi" "name" test"  -> abi = "abi", name = "name", test = "test"
+     * -"name"                 -> abi = null, name = "name", test = null
+     * -"name" "test..."       -> abi = null, name = "name", test = "test..."
+     * -"abi" "name"           -> abi = "abi", name = "name", test = null
+     * -"abi" "name" "test..." -> abi = "abi", name = "name", test = "test..."
+     *
+     * Test identifier can contain multiple parts, eg parameterized tests.
      *
      * @param filter the filter to parse
      * @return the {@link TestFilter}
      */
     public static TestFilter createFrom(String filter) {
+        if (filter.isEmpty()) {
+            throw new IllegalArgumentException("Filter was empty");
+        }
         String[] parts = filter.split(" ");
         String abi = null, name = null, test = null;
         // Either:
@@ -45,20 +50,18 @@
         // <abi> <name> <test>
         if (parts.length == 1) {
             name = parts[0];
-        } else if (parts.length == 2) {
+        } else {
+            int index = 0;
             if (AbiUtils.isAbiSupportedByCompatibility(parts[0])) {
                 abi = parts[0];
-                name = parts[1];
-            } else {
-                name = parts[0];
-                test = parts[1];
+                index++;
             }
-        } else if (parts.length == 3){
-            abi = parts[0];
-            name = parts[1];
-            test = parts[2];
-        } else {
-            throw new IllegalArgumentException(String.format("Could not parse filter: %s", filter));
+            name = parts[index];
+            index++;
+            parts = filter.split(" ", index + 1);
+            if (parts.length > index) {
+                test = parts[index];
+            }
         }
         return new TestFilter(abi, name, test);
     }
diff --git a/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java b/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
index 215e2ef..1e9aa33 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
@@ -69,12 +69,16 @@
             "at four.big.insects.Marley.sing(Marley.java:10)";
     private static final long START_MS = 1431586801000L;
     private static final long END_MS = 1431673199000L;
+    private static final String START_DISPLAY = "Fri Aug 20 15:13:03 PDT 2010";
+    private static final String END_DISPLAY = "Fri Aug 20 15:13:04 PDT 2010";
+
     private static final String REFERENCE_URL="http://android.com";
     private static final String JOIN = "%s%s";
     private static final String XML_BASE =
             "<?xml version='1.0' encoding='UTF-8' standalone='no' ?>" +
             "<?xml-stylesheet type=\"text/xsl\" href=\"compatibility_result.xsl\"?>\n" +
-            "<Result start=\"%d\" end=\"%d\" suite_name=\"%s\" suite_version=\"%s\" " +
+            "<Result start=\"%d\" end=\"%d\" start_display=\"%s\"" +
+            "end_display=\"%s\" suite_name=\"%s\" suite_version=\"%s\" " +
             "suite_plan=\"%s\" suite_build_number=\"%s\" report_version=\"%s\" " +
             "devices=\"%s\" host_name=\"%s\"" +
             "os_name=\"%s\" os_version=\"%s\" os_arch=\"%s\" java_vendor=\"%s\"" +
@@ -204,9 +208,10 @@
             try {
                 hostName = InetAddress.getLocalHost().getHostName();
             } catch (UnknownHostException ignored) {}
-            String output = String.format(XML_BASE, START_MS, END_MS, SUITE_NAME, SUITE_VERSION,
-                    SUITE_PLAN, SUITE_BUILD, REPORT_VERSION, DEVICES, hostName, OS_NAME, OS_VERSION,
-                    OS_ARCH, JAVA_VENDOR, JAVA_VERSION, REFERENCE_URL, deviceInfo, summary, modules);
+            String output = String.format(XML_BASE, START_MS, END_MS, START_DISPLAY, END_DISPLAY,
+                    SUITE_NAME, SUITE_VERSION, SUITE_PLAN, SUITE_BUILD, REPORT_VERSION, DEVICES,
+                    hostName, OS_NAME, OS_VERSION, OS_ARCH, JAVA_VENDOR, JAVA_VERSION, REFERENCE_URL,
+                    deviceInfo, summary, modules);
             writer.write(output);
             writer.flush();
 
diff --git a/hostsidetests/appsecurity/Android.mk b/hostsidetests/appsecurity/Android.mk
index 0218897..258192d 100644
--- a/hostsidetests/appsecurity/Android.mk
+++ b/hostsidetests/appsecurity/Android.mk
@@ -25,6 +25,8 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
 
+LOCAL_JAVA_RESOURCE_DIRS := res
+
 LOCAL_CTS_TEST_PACKAGE := android.appsecurity
 
 # tag this module as a cts test artifact
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/dsa-1024.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-1024.pk8
new file mode 100644
index 0000000..d500d70
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-1024.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/dsa-1024.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-1024.x509.pem
new file mode 100644
index 0000000..e230eb0
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-1024.x509.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICsTCCAnGgAwIBAgIJAP6EmkoBF8UoMAkGByqGSM44BAMwEzERMA8GA1UEAwwI
+ZHNhLTEwMjQwHhcNMTYwMzMxMTUyNzEwWhcNNDMwODE3MTUyNzEwWjATMREwDwYD
+VQQDDAhkc2EtMTAyNDCCAbYwggErBgcqhkjOOAQBMIIBHgKBgQCTDpv8gS5Y+Ehl
+oln6WT/MYBnywrc3tWDfnlY+9MpVDdB2+kcB7WrhobW1L+6ayKmlkrTaAFjiMPDf
+bdyA6hy3fDu1teLCb89R0uodfZa3MDXXlmqvBk4Fdw8fYijWI/q175e4Y5sNYO9+
+QZg8bBIZnxxCdbKASJ6NAHc50ts3vwIVAIebRw3HnYOZbo6rPoBmcBOxcZTLAoGA
+ch+0D7JrbqmR1w5S3VBtTnONLiBYnaz1Ri3Pfiw5FHKfJcfFcQopIOLJwfdBmY4b
+FLGV5u7DXeJNp16Nvl4MrsmVjkWs9MZVAp5RqzrN9JhVi4ShpdelyFjdWOXHPbc7
+NNqQpTjdkK23r/tCE6XkvkCiWm7Rt22LMpZA4ePALIoDgYQAAoGAc8SkppDzSUPH
+SpKrhrldRyh5m4wSH14ZE96mlSze9tRoSDo8hsA9/vGLgoN7F+3jYSvj8m42tmNt
+jZJWk7vPkJHC/9qoEGbVBY+aTNYwVJyKDJ07vZB9bLxpjD/yyQlsn7/vZTOS657c
+W2S817RgGGyGcCNRoKNig6i0k9fzE8ajUDBOMB0GA1UdDgQWBBSPwzoIjftVH2ke
+EJXtLq+bB50lzDAfBgNVHSMEGDAWgBSPwzoIjftVH2keEJXtLq+bB50lzDAMBgNV
+HRMEBTADAQH/MAkGByqGSM44BAMDLwAwLAIUH1GQcpqx8/9p9QfhCRMvcxrECM4C
+FH8ZULK91BMaHodbRMUtdxB9kIbL
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/dsa-2048.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-2048.pk8
new file mode 100644
index 0000000..cf63594
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-2048.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/dsa-2048.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-2048.x509.pem
new file mode 100644
index 0000000..705db39
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-2048.x509.pem
@@ -0,0 +1,26 @@
+-----BEGIN CERTIFICATE-----
+MIIEWzCCBAKgAwIBAgIJAK4uYtTAat4+MAkGByqGSM44BAMwEzERMA8GA1UEAwwI
+ZHNhLTIwNDgwHhcNMTYwMzMxMTgzMDAxWhcNNDMwODE3MTgzMDAxWjATMREwDwYD
+VQQDDAhkc2EtMjA0ODCCA0cwggI5BgcqhkjOOAQBMIICLAKCAQEAv2/yUkci8fnZ
+ppepy1kcOTIrbPJTW46Z2jKOWjHCTd1aqRFunz3gllpx/YDgjboNIYZf2jKhk2gi
+MgF+8OT0hEHQGXSofnqRoVljexA2nC3tPhVyjN14pQ7ZJXp/raHh1uCT5K7Lfafc
+8y5Cs180CdfisspANfCp10jFu1D2hKOLfggUA9efN05c0f2yOx/Pm9uEiz6ftLUJ
+UWgcJenx1WUk4Nb1qMOWgg9nKQyDiBxZKoVCH5/XJO0K225w6F4scol2hMdTRlA+
+9TGb5tvHKT+Y+lE7fBbcBSKzLT3pwD/T08ErpsIoHqRPamLGHeuamGzvXLHwI1UN
+cJNGg2nnCwIhAJz9K+Qpgg7sbqRMeRvIf2cuWRWbi4XnYR+IAGqgfYUZAoIBADks
+N3taHUnIvkcxTuEUiCSb+d1KMlvbZiH5zLVIyzi5kZNQW8L/gR23z8T6qngXXnFw
+tcTRcb0TDqR7iYPxsX3/x+jBjiApIgebqpnPdpiEAUfORZX7w6CpCNsp9Kqxb98z
+4PtKE9z/20Q3zKhqlwDm8uSjjT7E5xw/YpV8bg7YuQ5eQ8mkonipNXllf3qmDV48
+see/+QwIeBiL7jTjgeBv5ziL8BY2AYmfOwGKwmK9ERxJpIoxgS+5fFuA2oAQ8CwJ
+UDwwv5Wbz7NVkvljHK1Fh5u26ZHdeLT4qp4F0GamJcikq4MqFco6ToCvp8NoDNMZ
+MOno2k1IvsIwrIbrQJgDggEGAAKCAQEAuxbFbx2H4n4BqfbkC9tjn/Mg3zr4LZgG
+7v3FWpzpkbAcEcFCVIqTmJiRlsuf4ml/t9hflOvarfD6TesSc7gyGCJ/2QiqJcI+
+Vif5AKqZskQFlZ5BUMIMjPFMy1WtTVpEotmdbIOaQif4wQrz6SNFUOAXPBKRTY33
+HOLMoo8FRiZ1+uMu9PlUWYqMhSJg+rm2AQPt06D+JToXREaNkYjN0K97T2MTcUNh
+OWiliH/zFuF8N2s6IlNaCv1Yc4FoYEIRoS07dUxcjrV9KRd0TyU0q++rRPluytJP
+yAoyTIrfwa2SM5JR9RtdBZsPdR9Ckpy4ZKSJqDzTbCIU70zsGgHA4aNQME4wHQYD
+VR0OBBYEFL3koBjVHAySf8Xr196yqDT6VhwSMB8GA1UdIwQYMBaAFL3koBjVHAyS
+f8Xr196yqDT6VhwSMAwGA1UdEwQFMAMBAf8wCQYHKoZIzjgEAwNIADBFAiEAjowh
+laeXA/CUrHt6iH4u6edWGeZzyFGlpWsxssKTMBECIG2tZs/xnZVAtXioiIcH1CXT
+LN5AAzZ8wlNUKSvTc12j
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/dsa-3072.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-3072.pk8
new file mode 100644
index 0000000..f0f8983
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-3072.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/dsa-3072.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-3072.x509.pem
new file mode 100644
index 0000000..0284b13
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/dsa-3072.x509.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF3DCCBYKgAwIBAgIJAKmpH5wXPDbGMAkGByqGSM44BAMwEzERMA8GA1UEAwwI
+ZHNhLTMwNzIwHhcNMTYwMzMxMTgzMjU2WhcNNDMwODE3MTgzMjU2WjATMREwDwYD
+VQQDDAhkc2EtMzA3MjCCBMcwggM5BgcqhkjOOAQBMIIDLAKCAYEAscwotTL9jjwZ
+CpGRqXVezU9P0zY/wHFYMQB09JjgoCJRm0D9FZzmTnySJa4suwlwoduzgv+pkIkk
+nn0w+hL6LsblRTEuFj11o/fLLAZE4KmdIAPkCcH74HOnws4BwazJLWFtVEv+bdyj
+CmrI2urYWT5uRJwWZmkG4iUnoL/5FUv2pvpSOzu6EO+qFcFcWf3/VrQDaaP3jRRh
+iVCThxvX5xOrO24krrOFlHQufY0A6fHYQqII6EYac6tKTI+ltz121DYH914SHMe8
+0JJYpDVOatjTJADyg1AzHAKsyfTKHHpHbqkgU/CRtALEC1DUyLqQhHvBGpodmqPH
+r9Mbd7pXudw2h6O8uapAsmaFt/YdrSbd37UvhLJyyW0fodTjBTA0WiNs0CLTJL9o
+422Nt1cUDQS1JpsghAzmMWaavq7+QIRhpnMHL47p1jCZvcwMboMlcJwOCjyyZS0F
+fmaD+pEi56Lx+9XDblESM78crb8/lbvuohyrwIJciQmL0hQoKIg1AiEApYT1sROj
+BMB4FIQaS86VKdJ4h9OR13AraES3ba9WV1cCggGAI9LskZ7wcUna6nZyGT4f3bH1
+KSeD3602Yd86NKuB8QGr/QT5L+wFwCuvvI4V8P2lM4wb+q1LrR688f53WS4c0Kin
+/MeN4YtkQBzV4l04Bxrce//EcfQzUPDAr41Fwu2tA0BHE67trxGjNS7SzoFZUiDo
+d/aOZCVilFIay5oF2X8yeNcpTynsxTbGxjxhhgG2tS0fvxhbGF6rl4D0Ddskx6L/
+xjstzu0ADE8FNpDehuKqxzOisNLIJgc1INPQ06AmaUF1Pge74T2AJYPYwqfzArG3
+pj+l2iND0PM7lDeQCgivPAqhYrveoIqJe0NAEu/PiCnOW50hQ4F6dl9lzn9sGXTP
+5KxdR5OyG+Ki+nWTN8h3yOy9ZK7Gh8gUeqE3QVow4+1LhcO19C+X+NM588KbKsq9
+KRP5H4v238g6oF2wgbmPrYvqiwoa1qjHvUX7ZjQuIfrN9+lICflsHKtAtchuUIiO
+b1AWPeaJwAynTn2EeDsVd0e8bm+h+g7ZSDAwUOKuA4IBhgACggGBAJfW6T1BxtZo
+EacqR2TwTi9B3O93Zcj0OzDOn9UMahepcfaF1B3wq9UdJ4PPIC1U27CaEXEJNxgJ
+cIURfFPDXA6pLVEqrGgRX2u0FR1pmHVIxjBpvPJvO954+Hawp+ClU6PKLmxuVZpA
+VeJBx7C8/DU/58J//iuG9B6/mwzPuEoPmnGYMsfVCcEX8yQ2PZXyNGp+KnUygyql
+mMxpE8UXtH6mHYontjiw4Afxqwop3v/bG8eT5FHhpXoQDSN/oeGghDaq9DyIjCqr
+GXZDBvEufLYRgOvnpV6T0oMa9U2W2Trz3HYD6eX09FOhGnMWl9euYrSVRihAKBh1
+72ystvPy2R4wdAA5EQf7EsDdgt/QOMf/AvkaKHMP7DNK5BZxwPQ0KwRkLB+0vaDI
+Mnpu29L6TiixMxI1ihnZbR/U0v8H+/SlSjZaPNRQeuoV9d8t81miUqVSMLcpqNui
+ZljSCtoGfktPAbPyFwGenBkGK5oo0I381KTECMynC0R2P9CQUHegeaNQME4wHQYD
+VR0OBBYEFPRqMyQLPdq0guTx3YKiVxtWN+bPMB8GA1UdIwQYMBaAFPRqMyQLPdq0
+guTx3YKiVxtWN+bPMAwGA1UdEwQFMAMBAf8wCQYHKoZIzjgEAwNJADBGAiEAjcit
+8dFR02elWKoeRAounP9TE2aqDqd5cJXqXn0ssMYCIQCIINjXEYRovfVjDotKelRg
+5k0lmzMmx6Xfz8EgZDLovw==
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/ec-p256.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p256.pk8
new file mode 100644
index 0000000..f781c30
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p256.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/ec-p256.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p256.x509.pem
new file mode 100644
index 0000000..06adcfe
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p256.x509.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBbDCCARGgAwIBAgIJAMoPtk37ZudyMAoGCCqGSM49BAMCMBIxEDAOBgNVBAMM
+B2VjLXAyNTYwHhcNMTYwMzMxMTQ1ODA2WhcNNDMwODE3MTQ1ODA2WjASMRAwDgYD
+VQQDDAdlYy1wMjU2MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpl8RPSLLSROQ
+gwesMe4roOkTi3hfrGU20U6izpDStL/hlLUM3I4Wn1SnOpke8Pp2MpglvgeMx4J0
+BwPaRLTX66NQME4wHQYDVR0OBBYEFNQTNWi5WzAVizIgceqMQ/9bBczIMB8GA1Ud
+IwQYMBaAFNQTNWi5WzAVizIgceqMQ/9bBczIMAwGA1UdEwQFMAMBAf8wCgYIKoZI
+zj0EAwIDSQAwRgIhAPUEoIZsrvAp9BcULFy3E1THn/zR1kBhjfyk8Z4W23jWAiEA
++O6kgpeZwGytCMbT0tLsBeBXQVTnR+oP27gELLZVqt0=
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/ec-p384.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p384.pk8
new file mode 100644
index 0000000..f22507d
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p384.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/ec-p384.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p384.x509.pem
new file mode 100644
index 0000000..9d1403b
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p384.x509.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBqTCCAS6gAwIBAgIJAMRWS+CLIsxqMAoGCCqGSM49BAMDMBIxEDAOBgNVBAMM
+B2VjLXAzODQwHhcNMTYwMzMxMTUzMDU3WhcNNDMwODE3MTUzMDU3WjASMRAwDgYD
+VQQDDAdlYy1wMzg0MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE18hjdbk/HXGQNIuF
+xKPMAZO3PQnROO6izB/mHM1BKPpih2/51iMTFKn6KCU9NZt/Q4Z+PpZVLuawEWP/
+uoWwWIj+60vk25z47/Sr0icelSDGt9T9ujiNP6aTA5hc9gypo1AwTjAdBgNVHQ4E
+FgQU981MoejFjh0rbaGXODywOYvB32kwHwYDVR0jBBgwFoAU981MoejFjh0rbaGX
+ODywOYvB32kwDAYDVR0TBAUwAwEB/zAKBggqhkjOPQQDAwNpADBmAjEA/58rXa+F
+mB6JwB89/IAucpNlktjSPrH2tD63BSROvpUpXNy+p+OlJu4sCvY7HnwEAjEA0VWw
+QqUBFLQHFJx1JjMYYfT78V8ylY+Ns1lxrdvs29NNg45MA9uw/ZVMMHgTFNph
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/ec-p521.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p521.pk8
new file mode 100644
index 0000000..9c75e4c
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p521.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/ec-p521.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p521.x509.pem
new file mode 100644
index 0000000..a9b8194
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/ec-p521.x509.pem
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB8zCCAVSgAwIBAgIJAOxXdFsvm3YiMAoGCCqGSM49BAMEMBIxEDAOBgNVBAMM
+B2VjLXA1MjEwHhcNMTYwMzMxMTUzMTIyWhcNNDMwODE3MTUzMTIyWjASMRAwDgYD
+VQQDDAdlYy1wNTIxMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAYX95sSjPEQqg
+yLD04tNUyq9y/w8seblOpfqa/Amx6H4GFdrjGXX0YTfXKr9GhAyIyQSnNrIg0zDl
+WQUbBPRW4CYBLFOg1pUn1NBhKFD4NtO1KWvYtNOYDegFjRCPB0p+fEXDbq8QFDYv
+lh+NZUJ16+ih8XNIf1C29xuLEqN6oKOnAvajUDBOMB0GA1UdDgQWBBT/Ra3kz60g
+Q7tYk3byZckcLabt8TAfBgNVHSMEGDAWgBT/Ra3kz60gQ7tYk3byZckcLabt8TAM
+BgNVHRMEBTADAQH/MAoGCCqGSM49BAMEA4GMADCBiAJCAP39hYLsWk2H84oEw+HJ
+qGGjexhqeD3vSO1mWhopripE/81oy3yV10puYoJe11xDSfcDj2VfNCHazuXO3kSx
+GA/1AkIBLUJxp/WYbYzhBGKr6lcxczKI/wuMfkZ6vL+0EMJVA/2uEoeqvnl7Bsdk
+icyaOBNEADijuVdaPPIWzKClt9OaVxE=
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-1024.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-1024.pk8
new file mode 100644
index 0000000..7b4beee
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-1024.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-1024.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-1024.x509.pem
new file mode 100644
index 0000000..9498ec5
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-1024.x509.pem
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB9DCCAV2gAwIBAgIJAP0KtYjhFu3IMA0GCSqGSIb3DQEBCwUAMBMxETAPBgNV
+BAMMCHJzYS0xMDI0MB4XDTE2MDMzMTE2MTQ0M1oXDTQzMDgxNzE2MTQ0M1owEzER
+MA8GA1UEAwwIcnNhLTEwMjQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOOP
+r4Y+uCAihcVjey8JmdjyfhZXplVf3HnOQfvWcY97nKnJ7L977QiWajIn7iZRAdVX
+PamVrEbaU6uklgcJFG/qirtscOf6fMBf6GaP2PAhQG89MQnUt9rAjxUAakzWOBTz
+bH0gHRDEGQ30LCA1oSlbLldHz+zBKSC7nsSKYp+9AgMBAAGjUDBOMB0GA1UdDgQW
+BBT1x0TcWRB4i9JnU5pvRtrEv+95OTAfBgNVHSMEGDAWgBT1x0TcWRB4i9JnU5pv
+RtrEv+95OTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GBAKs024CvDYFv
+rj3GTXM8A9Jslg/86WukzEl/+PXDjbPljNV24RSsFVW5gO0ps6Q/EBkbllJP7xNO
+XmOUDyqUcvcwC1zzySqs8kJcF5GCuRXajy4KiEiA5VRmVUSShhnkYX7g1yXkhWrP
+Ps1fQArqHx84+naFSh9kVqu54QIykS7z
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-16384.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-16384.pk8
new file mode 100644
index 0000000..c8d2793
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-16384.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-16384.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-16384.x509.pem
new file mode 100644
index 0000000..22b6148
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-16384.x509.pem
@@ -0,0 +1,93 @@
+-----BEGIN CERTIFICATE-----
+MIIQ+zCCCOOgAwIBAgIJAOd3bpikuRKvMA0GCSqGSIb3DQEBDQUAMBQxEjAQBgNV
+BAMMCXJzYS0xNjM4NDAeFw0xNjA0MDQxOTM0MzFaFw00MzA4MjExOTM0MzFaMBQx
+EjAQBgNVBAMMCXJzYS0xNjM4NDCCCCIwDQYJKoZIhvcNAQEBBQADgggPADCCCAoC
+gggBALDYs7aIK08pNr9fdrpLmUVfSc+3n/RNU2e7o3fzwQf2IMExk/ZmxF/ORgAd
+pXPEkn7uOLYSp+fJHUgqsca+8HsxTN1ypKov0X3OeFbnBLXmsoXgjRzaMEgluupd
+B81xnAKE/Vb+HYaEJ4YP+3UgBLIItnwLtL6vdh+e4qQGF9KEAv+T+PdrNQF0EGWK
+weCaOuMKRKfSnNXMkgIgWgoEefsBXNOR/jRJVFxsnJlwsB2iw0FbKjrxnlmwBL+f
+A8YxdMoCLxjL0TuUEmRyd0jO7Td49kUIkW6ux/b4qOvcUPQiODXeayesJ1lmFepS
+ATjhgCz2+C3pcAJOPvOvC4v0+5OQ3YrU2kKsnj8G2ic3SdPUq4UUvQWqY+rCZVDH
+IqsEs/+XO++wMELkN3uiQcRIEO8aCug+VxMSRiyRSSNtxmcmedUZevbZ6+2leBtn
+AbLP33E5hC80A7WKuddQgOiA1yTUVxatZEaxHFVZlg2nzSYHipvwMVC2+zQ4yrKA
+mbNp5wiVUV5WLsUkYEuSwl+MG9vEjr2gTX+qLrvpIYS2AF/16SOEw5zQBPUcfVIz
+eJU+W//wwXdlNmA6qRCDXqLDBX1MQrChpaI2eRbv64k5C09LtEA5nt/lJt5dm8IF
+XpurOZqHTVG3CCS15SM8PyoApYKN0oM9+6Z+FDUOB+VbTW/hAqKYLNBJmNf8mRkK
++c1peoOAYw5iG8iaSD8f8bcIi3oFPMdt0Gs5vDoLjbWmK2s9P2wknA4hmVe7hvSy
+DMvyxj8j4BLadc3HafcXYPfoNPhfgoiZVLm6ijEj74iKeLSkef8F3x0Agulnitz3
+CWt7X6EXHbqR/0++VTqgnFDe+enf9oFzMsDDbOs59dpyGFSP159dTqJILimF5xUG
+Fw95hsTbdEblZ7Q2MiibB38ifz8WT+Pix72SnHrlcnKonv8Tkeoie0AP+dYkYXpC
+Dy0oIzl7Vhy1e99RjX8kKjZAfCuiQ7wnOGNu6V32UyKMvWD5E6mNLpsvyBRTxDhs
+ePpH5dZWbhg6WxhD68QG/Wi/8FRmc8/TPpPXilOG3HHtX6Q3yfGYHJB6/dJhWQQy
+iZawyEpcyZKjEyWoJayRsKSLb6gW6Idfc1Uf/yb6IHDRlYZEPF7JuznjLCaz2QC9
+8GCBGfUE9OGH+LtdMnsmn2IYEd1FtWrRGduG0HNKubmx8bJmc1HkYDQg3cksPb2o
+jwCND2ALGtTcR30yllmSmEJKpXBYB00iRvxvkBqCkL4THOXhN2V5uEMrS0r8GRZN
+QCvCoFKulPjITmlQ/ciVonN9y9qVeRbFE4ZxiiBxF41K/Mw45ugIqfg4ndJqbub6
+5p15nhYJIC2CbsVL5+1THmd+kompQhUo1ttwof0aHh3KLwe1uq2OEU7Tz71Ct5+G
+b5JjIAlQDuGcfsx3utJY3AE5ailtvaRNAz3FyTsZGkIOeqX4uswWltxGnuSMSbPi
+CPv7ngFXkytkK+3Oqs92XM8mhO1yqPzmm73+qZYDGFdy32C/Rr0enETmgkUFPToH
+28hMcOsEt+7L0GM6A5N708BaF9Csy7XTFz47Hk2CjaKTvP08Tl3bFPULrgJ5KCr6
+4hc/bVIDkU7c1lhDISJ1yuw4KHizmjuf4UeRBBDoB3MpPwZSeEkggGXuX1wkFApu
+RGhjCXQgFU9bNtUHM6Kj0tPQZrgsvx2wwBUFVOfPoej6afrJqpvep+EN1+OJCE4c
+AzuZ1CdE96vEleVbrq3BQaJbsm8JqHs7lAn1aiCK0semqAoXD4cT4L2H4E37IDlm
+PHsxIeTmgD7/TP3InuFB6sYvVM8moG1TLmtUJkpc8kkPBPNbTRHwuRvMGD1pSsP1
+aNbgKkEfGqL1iOrfoTCRGKDeDDxWGsxDOgW1hRs9wGzJuMQjl1Rlb11lnnX7UYyT
+UnD/yw7YaplScWwpsqntQewI59A4ad1wOJlabDUFwkD4i4ERTcjyea1ydE03qaOy
+0ItJbc8kjsEMWFAv1+y7/cxD7kALcytvBHhD8OVJ40qJrtwRsXnv2T74cTPh87qh
+3j2tjdJKVSLxwqg5ZdvIemnWmmFAPuRERResp5j5WLJcOFcXhbp4CAQLViRoktLf
+AKtgKSVa9FQLvombOq8GqWxqeGJEsq+8/X6UOj/RDPu8gUCdodmlxgC5BpJlMTfg
+9ElvHb4oRewPfc5MBV5i++8xagxS1+5NM6z+1qZfT+XJcJ/wFYyeSvGGdEgaDIVd
+XGqOFDmA20bUl0xWSM5j4At2CmymAn32i8FR5lNfB/f8tIGBlXQyrYzpAKoj6FrV
+3u43zKgYBzDTqNs61e+A8MScV5666gvpcOltFiaucc455JGiN2v7N+SAygWaX3nb
+jidmRaIAftup6kXVXxy1ZwpKCtUTqo0M+S/jO9clHy1EYaSX12blCL1B6OFpMRV7
+1foffUHwaPrMqqbPphgN4QRY2Ao2sKSliiP1T8s1T2iteEGiazCdWSOVVi9Acbo5
+DfeBlWwhW6OQpv1nMTznGscc4+ledP5yG5C6boz2aNwK6H6cpDfEc7tWTWhZN5Jm
+Jlra4pseqf9Lsc/Y4QMD1312C3Hu8EtJ/qlxEDhLnCW8PHxdlRsIkmcV8w+as/hu
+6/MlOYcCp9ae6nooFL7ZuDkdDWm84UXdce2ZVVGVoDa+RdpICnp79y/9CLxWue4H
+09VFEFUH//E6lOCBymUjTSO/DQ6z+ceb2W5B3WVV8gqADTDhAgMBAAGjUDBOMB0G
+A1UdDgQWBBQkHp1wX0Sfr0xz7xcip9UwEIFTLDAfBgNVHSMEGDAWgBQkHp1wX0Sf
+r0xz7xcip9UwEIFTLDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4IIAQAd
+FhlHg4E7Yp8kIOfZRU5Cma6wbOSd2eHkV28WHGdwpKsvNhzgQEj+scYWSS8geozi
+vqSdJCoMmY8hWJh4SY0ED1DjPMoRvE8OotyGoCJovvYQia+gbVneT8JnfV3fkdwi
+hpUmAhokrsHkBj0jp2Ubff/D5yflA+QPCmhZZnkow+5QHXtmpy8CL9Fzfonz5uq7
+yCV5uWRicczFbQw3pDSXKn5OFqXuC8H/8R6Caq2TkJ1LusVtZJevcHBkEQ6e+XEX
+kZ+QCNtHw0a67LQEPtMXSyqZ/zR0roqwT6udUgHhdvZjbbb9GDpTW3u472IY18E+
+bf+npZl9kyuv2kyK1d2IjL45TxjBr7vLbjsP2UsmZvb3Wfb/kiMscvTBcxOL7/WA
+GNJ0XifmJWiDTDC+gUBC7LRN9lG8F7ykrMTtMUNlhow5LpIi0HA8TH58yq3/ulGq
+XWpculy33kcVAFTMGh57r8zq9DwkeW+RWggvHO2422S1bFGmKpizKASTvY6iqo4H
+yKvE9uZ41WaEbpp9WKPIaeup+ynxFpcgwMCKwvs7Yaj+mVexv7CoJ9nrEhMOHDxV
+GRyWDdBoIi08S02JHztZBXp5NZ+hqey5HrO4dhrnV1nVYJmH89KcAlXMfTZ2YHsv
+R2+dm6K8ToaX+Irqbz7Xbv8WG/aAdUqMSWkFEss7OT7VZBUiAdFaWqg0D0wtWSSE
+jZJJs9ISUTClq+97o9BEH2sAebchLFP56nY+Bj/zHBq2qPxTKdKE5BH13KcK1fwO
+eNn8a3SlSEHraa0oV6VjgSoMNdFz7b7b0r/Z8L4PEASJgH+VaGRm2TtuVWFHSqvX
+015UGITk6YgAQ25MTprJc/oAd0dut+aCPtOVElfukYvdrbw1YYQ9tc7kU+AVrzaf
+ytWj2GYR5Slfhle0inKlBvbpLTAHs82bp2Dgy9ZSQzW9/gIvLvCt+Hj0kiSYNcbX
+W7Ai5z2i6XKE7DdQO0Uzt+1bXGK3j2PI+81lCw2ejCFwjdYDWQw9f2nzQ5FgeYwG
+tc6fS4GbJM97n0yH9rj0Jb25AummZGnEL11ytPpC6Nv9cQdCuKDbaWQuQyRMCLEm
+hHaqV6k/fI4Etvuo15pyfJ9w7Xrhc6emgdg2HzJ99lDGkzZAF/3FR7N5pLPk5E0/
+PPlXUSiEx17IeWp3rNt0YSMixkGz+EbKyv9RIZzm/LV4zAzs2ZyUHHavUgZ602eg
+89ppqafaBrCwIWB1jUmnHJop9YlXQ3hE7pAV5qf9GxZLwUdzJcyLte1/vkn1yt94
+nLOZPPWUwUjIaBOZ7e/g8fHBjvAYwyoy3toKVpvkhR48NvcYD8pQ9cB6rIL0JkWV
+nQEYeISlJCUOO3K2eZ3ZH02ftha5gLshcGRXy9NS+4fNxDT3H+102RqSxmKPIxV0
+onV9RyOxUPKLRGjCZBZxs5aSxTYjFJ591azt3yAY4vwCnnHqdNGFbTat/Zc8LUOO
+J26n5cOYFGKPvZVvj8jMNYC1wo+R+A+1FeYXBV4MSVxCB7tjBlbU6OIyZSWLZ8Vw
+LMcPbuZ7ESj1LeTONwS1vspZM8Y/M8+RXv9VA8Z998tnNopdU3izVC2z6Zn9hNNI
+XBDbSe6ZRwsjXrm5TZCBgA4ZE18MwxPVhntSvl87Gc3wF4hz4BOiZXmffrXK4nQJ
+aVA8E2IsriCV+GQBN/ui+w3U9LbtsHrbauhjrru5EfYohpuInwvgPlAnTztdv9u7
+ee8RhwaCa+MInZanD6pRAAcfM6O64CPxHZtfVW6JM42N7wQXijvYzJPVR30F+6o1
+C+KwySuMBOGxOctmzLj938/OMrxuLBOmv3PJvSnHV0pWtbR7r7jH3v0uUm54zH56
+Qo/Rm/Aqf+m4Si3Xtsf9zvc89sqG5v2TT882Joja76zlJfaS31QgbnLTmKtAHtIC
+mqfQPvt1LNEJIiB6FZDHJIW5Ccm7imsixerxCBBoAt/J/dhW6N+cjZ0EWG5NiSoz
+9LmAZv8iWyqK/KvdPXUopQWqkYUvuIyNCYqzTRLKudUMohefNwghvl1gSGp4IMZ/
+4LyrJHi9eCcD9Z65PJsRTua+742N2sdhFfU/C4atOUGSK9x/Dl79Qkgsl6HqAoce
+HXiHAIvoOqC+jzEkjjxow30BzJeGsZoFwNvMUW7HcQ523DiIOx6MX8oQyKEo+W6C
+ayFvvvT3qHu2hL2ZxOXE+rGyUJnmwqctz4ChLvyYXa/eNrycs382x2U5XNXgXzNT
+3bwB9B+LnKSMJEB+UvHdbBcafYyevLptbF5xiiiUA0P3fq61AfmNiCzJWb+kaO11
+oHHQNWyG/fO49u3bZJkhvlsk8GXAp9uTqdW7YAqxjy8NohFewmtpTJPE62XKIqiq
++dqo4nUT761iaUBxgyj1v5jKcXT2JiEMnEe4AN7pZJ01pCNXQrXl+6ru4TVV3tpy
+OsDJ9UfZo8xZXEAJ/gvSyiih0xq6xhwGuUyExC3GldBz2frveWImxVEiqQIdHULH
+WwB6eAm9T1f+2hOGq7AB9Jb8CRyQniJWXtWu9uJBt+XwSt5lN6VUjeLt95SitvjO
+llqs0zhvTf52H8siwaO83Cui78iamqv7jVatB3JYW71S5cOyZ/x5Z5FYqKi8/wjO
+L4OyUs54kfcJllsxAmS014UgcTrJpbMNw7jSzLX6FxT4MEbyARK8wWQfEZQ2tCeo
+IOzfcYvlY05mG0KSzs6ZGBrWRZQDPcbJ0CKNSLTFbQ==
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-2048.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-2048.pk8
new file mode 100644
index 0000000..105f7e7
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-2048.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-2048.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-2048.x509.pem
new file mode 100644
index 0000000..0e7b38e
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-2048.x509.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC+TCCAeGgAwIBAgIJAI41MGzdARX3MA0GCSqGSIb3DQEBCwUAMBMxETAPBgNV
+BAMMCHJzYS0yMDQ4MB4XDTE2MDMzMTE0NTc0OVoXDTQzMDgxNzE0NTc0OVowEzER
+MA8GA1UEAwwIcnNhLTIwNDgwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQDQ4JI1EJ239V4wss0jpVlZMudh2/kARCVdoBgsRQuvc2RNnO23Eyynlt9UN+Dc
+NRdQIhbCpVTjdEl/bePECHlqg9NE3frAj5GebiUdWL6A/idKsZA1nAKyIgxxjcnu
++38OcrlO6XOm36euxGfd/ULrghZGXzMVFq4uLiIv3DqFkUcIlE0BvUiUoNwpopV4
+MKj1GQgoaEObJG5xkMBKO6vg36VfJ3s3V3r48uJxYGhhBZEB0EpoXLd4i0piAB8S
+MLb0Ek6wA/HZ8A2rdnStk1wl/83OM1jO0uB3hyfJpqIijlvNGnrloYyyOIqS0LGH
+nxSJD7goASH2Ef0h4yxbsOvHAgMBAAGjUDBOMB0GA1UdDgQWBBQXAi1zEH84mzkS
+62ohswGGWSwdbzAfBgNVHSMEGDAWgBQXAi1zEH84mzkS62ohswGGWSwdbzAMBgNV
+HRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAB92T5toLkF6dLl65/boH5Qvub
+5wfIk0AD12T3t3kYWQFOH0YDCHNL3SfmrjYM/CwNJAd1KuCL5AZcn0km/n0SFXt5
+8Ps/MBcb0eK1fYezeEehKUyt5IBgDTKeQOel6So8rGuQRrDf/WV8rt6fugkIODFx
+sB3oj4ESaGXbvmvWD6q4a3koq/nV26kALchnAr7/FTNq3HEIQ1BDr9pldVh1gEV/
+ohHKcQP4M22Es7lredzpIcb5K6Ko/UtwsSRtHnoOjwmb+L/FsgAJsekmcJG5TK1X
+ciIsrrNFDCYzf/d9O1PD/V95kB7460qMzrGWZpc3mLe+OnmVMq6c4omOtIKl
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-3072.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-3072.pk8
new file mode 100644
index 0000000..163e06c
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-3072.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-3072.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-3072.x509.pem
new file mode 100644
index 0000000..0f3cd14
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-3072.x509.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIID+TCCAmGgAwIBAgIJAN8aZ+YVywdhMA0GCSqGSIb3DQEBCwUAMBMxETAPBgNV
+BAMMCHJzYS0zMDcyMB4XDTE2MDMzMTE5MTQ1OFoXDTQzMDgxNzE5MTQ1OFowEzER
+MA8GA1UEAwwIcnNhLTMwNzIwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIB
+gQCcgu3kzCLVWeUzwO5vhwWFD4rCJVavnVJjA4hz3fg9wsh8wpK0D39a8iyKS714
+5fFF/EsPpoKo6b8l9GVHfrSzJSa0rMcQ7+GHLyfG+8Wt6cnGwb8m6FOMKM8YAlUO
+zVL/WDZXBGvHu/gmZXM0ZbCy1cFBy5/kcGF2zF/fa+a8n4fUiQlbGC6y5iXKewMF
+z5/tFN4BeShBSNxGJVNOut/bLOvpGoPQVsteFlUgiSOPuXeiMeXDDEMEHbY7u7lB
+Fmjs5yAdXaLtnsJD689NdfIDZYHsiBRf7sFNWWNg4gE0gEPhN0QkC2Bkak80t2Mw
+XNakB7gqJ7Vsy+ZPBmhzMzeZbrK9cZXgqNNlxmraHycGzPif4sqmpy1/xFxNqOQh
+n2cc0fd2RG0ql1T4qO0U2b2NQzNMcgrtBW2E1UUUVukVJLCa7RKyt7yq7uUqeCYd
+MxNfvWYBSCzpZMvTI7jq6HcCqQOfW8nkE/z2IBdWvBi3yIdgKSsW0uZsW2/1+KlJ
+fhkCAwEAAaNQME4wHQYDVR0OBBYEFLGsv+jET2b4cWyINayy3qf/U7izMB8GA1Ud
+IwQYMBaAFLGsv+jET2b4cWyINayy3qf/U7izMAwGA1UdEwQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggGBACLyVVZrgLXL0PUAS2WwZruWj9q7lVnzLMla3u9j/fSLnlPK
+/YcuQh/DqovNkPjFrItww4VfLxkQNsdOccAMHWA2rnWivOYnS1q3gM56e9KN/fEq
+yRc3ltZCPvEoFnFEVtVfmgZJGV0xBLZUFHnPjlWtUYXS8pR89x/Klwy5aaJ9OcGW
+SPaI0I3TyFHCb92Dtfdehtdu8YCDrwTyaYLHvYdNQFDrJ20I8WNsG8RwklfAWNwZ
+IJ5fQxwHiCKxvdaTt2NYUSm4R4kEQCgklrgnaEy2kzDVKp4GjQwVrsa1btK+Srrd
+gtIqB+azx3XziuLi129qJGeZsof8ylN5eYmw0r57d6OPB/xj3roBsB77t4d5jEhl
+Y0BZ93t2HWvXJmuolf1JcauDOcGhxxgdiWdcOWeSABH3cNUiilRfs8HRwSzZwB5E
+RyjvKBdGirUAbLgri+8t9165gaz3wVhP4xkcD4e6LoupWHarAMKunMVGVbCOj7mj
+AUPHJ3Z+HhUKiI/q9g==
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-4096.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-4096.pk8
new file mode 100644
index 0000000..0f498e5
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-4096.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-4096.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-4096.x509.pem
new file mode 100644
index 0000000..704dcbd8
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-4096.x509.pem
@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE-----
+MIIE+TCCAuGgAwIBAgIJAIhxrQmG+dcZMA0GCSqGSIb3DQEBCwUAMBMxETAPBgNV
+BAMMCHJzYS00MDk2MB4XDTE2MDMzMTE1Mjg0NloXDTQzMDgxNzE1Mjg0NlowEzER
+MA8GA1UEAwwIcnNhLTQwOTYwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+AQDTPhE7i4Bv3BQG1ifMPZfTGA1ZvE+mQWOgQ1q/3AQz23I8pIaoj1wFbYDvnTYG
+UCDnlJqKvwL4mrAnxvqTxm+0g/WFOoBKFoNY5OhgcDfomNEFQajY9bgXaNiwEYDU
+0X+q+2KAnr35MF7vdEaHcN8gFh15wObVXmlerMIOWejnwrM4MOXjGjNXtiB+Dg04
+Fb9eHufZ+s1dKNAojD08mUJkxTC1gjmBKPr8hOAPo9ay5NZk6mGaI1E0U5NbIpDe
+0EhYxRXkDjP7f6BzbhFEupCOzZNMC5CxD8fsmku1CaKBayGpsxktYFxsw1RFVTZj
+3pKYnM1fJBHj/hU+7zy60MZNpdU6i5HVa8FPldwAxv6P2dz0wIl9S3rrqDrd2/1p
+r3rKNrMbVo7wzZ8euVhmjttsRvN8NykCniX6oWxuX7EFQxT/ZM0xk055gMMW7xbr
+oLtPAJ1Lk7R6aTCS+ObrhBgS8+38sIT8rF/CCz2KQ68iUpMmMBz+dkYsDwHPq7vG
+wIy8J7fwzTLqUbyO971+4MD9/9HbqfjRAsjfnSz8HqfyHrSDKeAhgqlr8j8DtQ7X
+B2PIZIEmyN//A13xfZQ63c/KR/yf9nPig4KfHulODfWXBD+2T5kzakTSn4My37FF
+mzG0giMMJ3zGs4QpGZAKFGdwhUq6nAAqEKYo+dptlFhbzQIDAQABo1AwTjAdBgNV
+HQ4EFgQU+f3rdfojsysUqNHmjE4c+0I8YGUwHwYDVR0jBBgwFoAU+f3rdfojsysU
+qNHmjE4c+0I8YGUwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAbOd0
+bKbaeGNsinFSck4niiHDhkeD7GhsneReA73LDJVwAsr5SLAYlmZL/R+1Jw2FGa5m
+82q8412xoVxqAbsz/OrBjoW+5RjAUpHSv0vo3Ny9EpFDpRI1yO8EFU2PhpbcC8Av
+101/oBA8tgKDKgb9H9GrnuqKqxLvrOKDle0TEWAb4X+yyuLSneU6UZTn/g6hhKMw
+pRcsCkwwKa2266auq93NA30Xb1UME5med/5fBKzjL7TvA8BTbr8EdHxjbPmnyI1n
+iVQJnkvvk6rDRcWeOt+lP/pmvaCcVFp9FJHlWmxrus7x0PuH8WxecVl6PeV3MLyR
+HXwGLzlqJWFm753FP3sTV3xNqemo1IhtlHR3jgU8Y7Ixq2Ljjs5izucqM+u2Ioo/
+wbzlhjfRmxqGE3RWvq6Vv5C22Th3hEA7PDUKAh1/cvUwZxOh1Wa9Nedhy0SUXAR8
+nY2GHJEN6QmR1ZAoyABHuPqk1IjduDONo0usGk/iYIFMgfwitc5Tv4gdjjBLburF
+NRU3QkoT1twPueb4Xnvmb/yHmTmqm7MM4OlkmTSpYRci8C1JNChdqIjNSF36Flnm
+DEMqP6petbkZcORD7UtgoB+DCPyBWybtm/GDOW2v3CWo94Q5A1yRDpqyQOTIJChe
+sssLUtp3bfmTSFFMfmsovynUlFpsazeFKjQOkYQ=
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-8192.pk8 b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-8192.pk8
new file mode 100644
index 0000000..cc7a7ec
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-8192.pk8
Binary files differ
diff --git a/hostsidetests/appsecurity/certs/pkgsigverify/rsa-8192.x509.pem b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-8192.x509.pem
new file mode 100644
index 0000000..42f1428
--- /dev/null
+++ b/hostsidetests/appsecurity/certs/pkgsigverify/rsa-8192.x509.pem
@@ -0,0 +1,50 @@
+-----BEGIN CERTIFICATE-----
+MIII+TCCBOGgAwIBAgIJAMMCN6DTJaAOMA0GCSqGSIb3DQEBDQUAMBMxETAPBgNV
+BAMMCHJzYS04MTkyMB4XDTE2MDQwNDE5MzI0NloXDTQzMDgyMTE5MzI0NlowEzER
+MA8GA1UEAwwIcnNhLTgxOTIwggQiMA0GCSqGSIb3DQEBAQUAA4IEDwAwggQKAoIE
+AQCt2gaOPSTn1A/WkapaytoE2RGF5nBzlfLocagG+0Bgz0RH3QQq0xBEmQivmbj4
+egyKFQQ9dYrefXRnayLQvHpfeT31QXR3iKOfMnvtxK9UnkXo9S/T+czyj91Ox51w
+HFUyMlXjFs8btxi6Lpkrgl3jmL+e4/WI8khvTrdszrO8rBHBYlD8Y7SAvPcVczYq
+nn4m6Jd0/abR5slHiyGtkTREoHmW/u4r4PfTzanLyzcsWH9/td+sYHcu1Y0XTWTR
+x2qrUmpD+7X5cvXP9rsECU82dtnyPZPIHBqzfLJ8oGELsJxgVZ0u9gW0tlmJQdVo
+Q0QPJSWivnNxPl1czJYbXimbY3Zh5hCzdyNqQewVx6iNsNh008JsXJ5/yvJQgLgZ
+UR2gWZMGzLc4V2wiqxuLzELt5RoXPehAdAiOLQu/3Fw+u4J/d7NEwpKgpdDGyG/U
+9nV6mjvomcgOdWKblaRAeiXauYy/MgW68kIu4O4SoKWRRmOF2p+tch3aDKw9M89O
+88QhEzbzDsioAxeOAqL7th3bSPZ2fX05xtM2vFK71QFM41q+FOL+062Ev/VJyU4g
+kxK643V+Cxso9CZEVtFfkNnVIGOI2h8knkOiLtbMnCx/hcxuZLm/XvYQxOO/7ScL
+rkHLUuKu/dK2ksDn8yBgaHfVlHkMmVoSll6fKB+UXpPX7xClrGQAFpVUji5oZN0s
++EcMQdcMtsb6LxnwC9XS1ELQ5FQGuJFatwY9RSV3cbwI6kNKaZiB5sDDAaAHX9GU
+U3EA2fm0u+4UFOSSmYTfx/jl0V1NMQ1oOAY9QMqzckMo2y9cepLQ3temQ/k4bNqj
+rYB3POdqS9OoT74UKU8gg9rv01PaFlLHhPKwVc+MjY36aVefbfk1KZzBpm2twUUm
+F0kz4pU3BYj0aSrTeKWaTLjdn4ndGMSe3QMQQ5GUchWCcygTyID8Wx8+eDzPIs/U
+sc++7fQRuPawcd11oQ7wTjWIjr7VnsV8hiHSyMupEad8HuBt8CNtDf/m/hD1LsEf
+0dY8nDGSPvV/ih2YqTfhcac65D4JKKbV5x65aEwM7frYwi9QsB7CK2xLMHnatp2a
+TRcA24VEsaBP2+UNSLyxkOeeuzSCksHLPBWkVfcRbKUeD9x4Dtwf2WsUtYjGzOQ7
+ApLBB4XHe+GPr/i+PmJP4IDoU1Mifbjla8rz2ZuebZgPnyV7nSvkG/FUqUYpa3Ut
+LY0nF/2dDRF0NirbWuB4Mkk/KlxCQ3w8EZFY5u6L/ee23WxbnVOEQJBtKh7/I/UV
+2dGqoVJx2UqT0MpjUCFjx+KjWvaEt+FfmjfRRqQfHLkJlYly/YdeUrGPdGgJNr0C
+csnZkAZmKDo4OVv+wVduHxHfAgMBAAGjUDBOMB0GA1UdDgQWBBRdiMpGc1L++yQc
+MtftoeGuLwJ+PzAfBgNVHSMEGDAWgBRdiMpGc1L++yQcMtftoeGuLwJ+PzAMBgNV
+HRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4IEAQBo9lUFyV8jI0IpcQLC7hC0ILxx
+6DsDw/YpMd9lRyujKa//OVJOEO3Z+SalfoLslMPCD1eeJBxgx9/xTMxZUrunOMJu
+Ddxc5RypVwdt6NOUQ3pNYU+Qkp73aZzakm6/i1LQDOxGf1PaZooPqXaKMfyb9CQ+
+M5wR9XsLDAyQPlylft3cWsp7DaPsrcp7Sn5u33TtvCDgfMwbKZrzzmCdAHS52p0A
+czMpDgYxhxCuHPwN6XSAxlrWnfpkOsdKneiVr4aDm1fp61PQg+sOKNCNJCMmUB50
+XFj14qLmvjLERNl2vUfDqoj6DxC9OceioZljzFM2d8/DEC1/YUT8AGYZQt0ISLlq
+QW4e4iIxXxVNKwXvJZMCd3z4XX8SvAOXL0+WrOffgkQQpSr2jBXKFe0BpCUnzVkN
+jw/bVJ89jrqfupExJ6kKTLzI+H2u/7LgZUn9/QlvhWR3IL1nEvCCOPHXTreuUp2U
+KauH7WQU+mzF/K+obzYiaPc53dz0C3JcvWgv5cBbhDUsGsziZLPkR3r5TvpTNF3t
+c3Ky84q7CfOKI+hGN/S+BNSv+TdA5uOG+h8GJ6SAwVpimzguhx2/iRg7OiHmhoy4
+UfsCF/QdoF3cEoSMMzorOIM+szZ+XggJMbtWzIv4NAL2TCKJcpB6t0Uxci6JN6lM
+tnbq78QxeOoJ3D3g6ZQoGvCdKwHcMQunS2MK75j9hckX5hR+0xnH++bI+D3qXaul
+zCOAcMoGpM7WgyzAc3mh9aAJFk1J9OYzpFY34nX2cDMc0xtI2s9p2/8X14ir5suK
+R0rqm3BZewDaQVNtrZCm/sch1I0cN4GomvxZ+2xD43vsZm8QEB2fyTvazg6kW2O9
+G0coUmszwI63f7fVx+wzZZxS24N17lIO36hjBq12SKDz9C3cIOZpPYdcaNxDyiwq
++RojbgUnosJji+xZtyK5Bf1kNB+jNoNT5OrWCXCR62Z5CQ+fAdlz4NPdibYnwscF
+SD8OA2I7UIT42KAuDBEMKVXe4SlhqLzOdqXwZ7h/ZxyUlY+zpwLO9vfLVpqZiavl
+bx+RO7lkvxPGEtM4mjXt5dNx2rgML/lXSE63qaqspYLJ806A3GE0918/b+ZDfvzG
+HLbeqIVtAlXwOGFLdifLvsgFybQ5yriR/yTlHXN/T8K+Q6wPo3uNkKNgUDq0FmzF
+N9UDQ+VFAdwaGPfBox3okGPoD6/HdiokuwZm4mlioHjZc513qhDapS3fJcXV6tu9
+OhIPBJ5NXVw3IVXwB+eskd2W5y8QlHZKBNTwzc/PBqL93QA2PxOFispDtevAuyTq
+OhRConYsMhoLf/9NqhEsyKVhwtYhYrUh0Q+hCiAg+YpjKuE2YJoUNMVyF3dY
+-----END CERTIFICATE-----
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/README.txt b/hostsidetests/appsecurity/res/pkgsigverify/README.txt
new file mode 100644
index 0000000..fca2b11
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/README.txt
@@ -0,0 +1,3 @@
+APKs in this directory are used by PkgInstallSignatureVerificationTest.
+See that class for information about how these APKs were generated.
+
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/original.apk b/hostsidetests/appsecurity/res/pkgsigverify/original.apk
new file mode 100644
index 0000000..2993c2cc
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/original.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/two-signers-second-signer-v2-broken.apk b/hostsidetests/appsecurity/res/pkgsigverify/two-signers-second-signer-v2-broken.apk
new file mode 100644
index 0000000..fcf154e
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/two-signers-second-signer-v2-broken.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/two-signers.apk b/hostsidetests/appsecurity/res/pkgsigverify/two-signers.apk
new file mode 100644
index 0000000..f11760f
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/two-signers.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-two-signers.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-two-signers.apk
new file mode 100644
index 0000000..f096a56
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-two-signers.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha1-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha1-1024.apk
new file mode 100644
index 0000000..0f0f016
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha1-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha1-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha1-2048.apk
new file mode 100644
index 0000000..aa30612
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha1-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha1-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha1-3072.apk
new file mode 100644
index 0000000..68edee9
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha1-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha224-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha224-1024.apk
new file mode 100644
index 0000000..938ea7a
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha224-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha224-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha224-2048.apk
new file mode 100644
index 0000000..2f0002f
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha224-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha224-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha224-3072.apk
new file mode 100644
index 0000000..13b4bcb
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha224-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha256-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha256-1024.apk
new file mode 100644
index 0000000..b1bf280d
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha256-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha256-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha256-2048.apk
new file mode 100644
index 0000000..8e7415f
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha256-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha256-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha256-3072.apk
new file mode 100644
index 0000000..65f8238
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha256-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha384-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha384-1024.apk
new file mode 100644
index 0000000..f5db0e4
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha384-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha384-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha384-2048.apk
new file mode 100644
index 0000000..d18a9a9
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha384-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha384-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha384-3072.apk
new file mode 100644
index 0000000..641ba50
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha384-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha512-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha512-1024.apk
new file mode 100644
index 0000000..dd8ab61
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha512-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha512-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha512-2048.apk
new file mode 100644
index 0000000..129a335
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha512-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha512-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha512-3072.apk
new file mode 100644
index 0000000..41287d7
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-dsa-sha512-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha1-p256.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha1-p256.apk
new file mode 100644
index 0000000..e9a0d90
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha1-p256.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha1-p384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha1-p384.apk
new file mode 100644
index 0000000..848cda0
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha1-p384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha1-p521.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha1-p521.apk
new file mode 100644
index 0000000..397e6db
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha1-p521.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha224-p256.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha224-p256.apk
new file mode 100644
index 0000000..5127d60
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha224-p256.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha224-p384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha224-p384.apk
new file mode 100644
index 0000000..b5d9d46
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha224-p384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha224-p521.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha224-p521.apk
new file mode 100644
index 0000000..f3aa1d6
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha224-p521.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha256-p256.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha256-p256.apk
new file mode 100644
index 0000000..02b8a31
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha256-p256.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha256-p384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha256-p384.apk
new file mode 100644
index 0000000..5c4bf7b
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha256-p384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha256-p521.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha256-p521.apk
new file mode 100644
index 0000000..3a91ee5
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha256-p521.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha384-p256.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha384-p256.apk
new file mode 100644
index 0000000..ec4a42e
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha384-p256.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha384-p384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha384-p384.apk
new file mode 100644
index 0000000..c3c3e0a
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha384-p384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha384-p521.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha384-p521.apk
new file mode 100644
index 0000000..5be8ac5
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha384-p521.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha512-p256.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha512-p256.apk
new file mode 100644
index 0000000..60090a5
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha512-p256.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha512-p384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha512-p384.apk
new file mode 100644
index 0000000..63f6780
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha512-p384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha512-p521.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha512-p521.apk
new file mode 100644
index 0000000..53ae508
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-ecdsa-sha512-p521.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-1024.apk
new file mode 100644
index 0000000..fe50da7
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-16384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-16384.apk
new file mode 100644
index 0000000..3ce1737
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-16384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-2048.apk
new file mode 100644
index 0000000..5eb6dec
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-3072.apk
new file mode 100644
index 0000000..451f336
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-4096.apk
new file mode 100644
index 0000000..a99a670
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-8192.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-8192.apk
new file mode 100644
index 0000000..10f4654
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-md5-8192.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-1024.apk
new file mode 100644
index 0000000..f31e649
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-16384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-16384.apk
new file mode 100644
index 0000000..784e569
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-16384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-2048.apk
new file mode 100644
index 0000000..a2801e5
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-3072.apk
new file mode 100644
index 0000000..8d9fccf
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-4096.apk
new file mode 100644
index 0000000..3e36a40
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-8192.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-8192.apk
new file mode 100644
index 0000000..b8f979d
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha1-8192.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-1024.apk
new file mode 100644
index 0000000..d86ac4d
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-16384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-16384.apk
new file mode 100644
index 0000000..7656ece
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-16384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-2048.apk
new file mode 100644
index 0000000..4971db7
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-3072.apk
new file mode 100644
index 0000000..ed7f3f5
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-4096.apk
new file mode 100644
index 0000000..7d47560
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-8192.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-8192.apk
new file mode 100644
index 0000000..99bcba2
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha224-8192.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-1024.apk
new file mode 100644
index 0000000..46d3e61
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-16384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-16384.apk
new file mode 100644
index 0000000..21bf67f
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-16384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-2048.apk
new file mode 100644
index 0000000..a952f1b
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-3072.apk
new file mode 100644
index 0000000..db6941d
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-4096.apk
new file mode 100644
index 0000000..5bd3d0d
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-8192.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-8192.apk
new file mode 100644
index 0000000..d8630b6
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha256-8192.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-1024.apk
new file mode 100644
index 0000000..9438016
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-16384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-16384.apk
new file mode 100644
index 0000000..bb0caf0
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-16384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-2048.apk
new file mode 100644
index 0000000..81a0258
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-3072.apk
new file mode 100644
index 0000000..b76d7cf
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-4096.apk
new file mode 100644
index 0000000..2583f6f
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-8192.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-8192.apk
new file mode 100644
index 0000000..f0b47f6
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha384-8192.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-1024.apk
new file mode 100644
index 0000000..7c6ff19
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-16384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-16384.apk
new file mode 100644
index 0000000..8cf9eba
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-16384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-2048.apk
new file mode 100644
index 0000000..58676e8
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-3072.apk
new file mode 100644
index 0000000..2f4b23c
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-4096.apk
new file mode 100644
index 0000000..b823de3
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-8192.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-8192.apk
new file mode 100644
index 0000000..ffa6be1
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-only-with-rsa-pkcs1-sha512-8192.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v1-with-apk-sig-block-but-without-apk-sig-scheme-v2-block.apk b/hostsidetests/appsecurity/res/pkgsigverify/v1-with-apk-sig-block-but-without-apk-sig-scheme-v2-block.apk
new file mode 100644
index 0000000..a194a2c
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v1-with-apk-sig-block-but-without-apk-sig-scheme-v2-block.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-apk-sig-block-size-mismatch.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-apk-sig-block-size-mismatch.apk
new file mode 100644
index 0000000..e657a80
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-apk-sig-block-size-mismatch.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-cert-and-public-key-mismatch.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-cert-and-public-key-mismatch.apk
new file mode 100644
index 0000000..5fbe97e
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-cert-and-public-key-mismatch.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-garbage-between-cd-and-eocd.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-garbage-between-cd-and-eocd.apk
new file mode 100644
index 0000000..9360383
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-garbage-between-cd-and-eocd.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-missing-classes.dex.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-missing-classes.dex.apk
new file mode 100644
index 0000000..0f1350a
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-missing-classes.dex.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-no-certs-in-sig.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-no-certs-in-sig.apk
new file mode 100644
index 0000000..692c6b3
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-no-certs-in-sig.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-signatures-and-digests-block-mismatch.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-signatures-and-digests-block-mismatch.apk
new file mode 100644
index 0000000..fb397a4
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-signatures-and-digests-block-mismatch.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-truncated-cd.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-truncated-cd.apk
new file mode 100644
index 0000000..d2e3e8d
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-truncated-cd.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-two-signers.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-two-signers.apk
new file mode 100644
index 0000000..697b046
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-two-signers.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-unknown-pair-in-apk-sig-block.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-unknown-pair-in-apk-sig-block.apk
new file mode 100644
index 0000000..a506bfb
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-unknown-pair-in-apk-sig-block.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-1024-sig-does-not-verify.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-1024-sig-does-not-verify.apk
new file mode 100644
index 0000000..18a4409
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-1024-sig-does-not-verify.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-1024.apk
new file mode 100644
index 0000000..9c8232f
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-2048.apk
new file mode 100644
index 0000000..1d679b1
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-3072.apk
new file mode 100644
index 0000000..6921479
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-dsa-sha256-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p256-digest-mismatch.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p256-digest-mismatch.apk
new file mode 100644
index 0000000..4cfc49c
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p256-digest-mismatch.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p256-sig-does-not-verify.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p256-sig-does-not-verify.apk
new file mode 100644
index 0000000..0339d39
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p256-sig-does-not-verify.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p256.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p256.apk
new file mode 100644
index 0000000..657f1f9
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p256.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p384.apk
new file mode 100644
index 0000000..326c681
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p521.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p521.apk
new file mode 100644
index 0000000..7fcb887
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha256-p521.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha512-p256.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha512-p256.apk
new file mode 100644
index 0000000..5942916
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha512-p256.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha512-p384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha512-p384.apk
new file mode 100644
index 0000000..82aa6ad
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha512-p384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha512-p521.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha512-p521.apk
new file mode 100644
index 0000000..fde4294
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ecdsa-sha512-p521.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ignorable-unsupported-sig-algs.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ignorable-unsupported-sig-algs.apk
new file mode 100644
index 0000000..165b262
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-ignorable-unsupported-sig-algs.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-1024.apk
new file mode 100644
index 0000000..5751fbe
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-16384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-16384.apk
new file mode 100644
index 0000000..a832366
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-16384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-2048-sig-does-not-verify.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-2048-sig-does-not-verify.apk
new file mode 100644
index 0000000..fe6be6f
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-2048-sig-does-not-verify.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-2048.apk
new file mode 100644
index 0000000..90ab764
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-3072.apk
new file mode 100644
index 0000000..a3569d6
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-4096.apk
new file mode 100644
index 0000000..101602a
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-8192.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-8192.apk
new file mode 100644
index 0000000..1c9f131
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha256-8192.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-1024.apk
new file mode 100644
index 0000000..e95e312
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-16384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-16384.apk
new file mode 100644
index 0000000..2b332b1
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-16384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-2048.apk
new file mode 100644
index 0000000..5e5863e
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-3072.apk
new file mode 100644
index 0000000..d587865
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-4096-digest-mismatch.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-4096-digest-mismatch.apk
new file mode 100644
index 0000000..72f5dba
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-4096-digest-mismatch.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-4096.apk
new file mode 100644
index 0000000..1189d8a
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-8192.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-8192.apk
new file mode 100644
index 0000000..146534e
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pkcs1-sha512-8192.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-1024.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-1024.apk
new file mode 100644
index 0000000..1331d35
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-1024.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-16384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-16384.apk
new file mode 100644
index 0000000..a205741
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-16384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-2048-sig-does-not-verify.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-2048-sig-does-not-verify.apk
new file mode 100644
index 0000000..f90d226
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-2048-sig-does-not-verify.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-2048.apk
new file mode 100644
index 0000000..8bdfb45
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-3072.apk
new file mode 100644
index 0000000..d36731c
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-4096.apk
new file mode 100644
index 0000000..8e190b4
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-8192.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-8192.apk
new file mode 100644
index 0000000..c879ffe
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha256-8192.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-16384.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-16384.apk
new file mode 100644
index 0000000..d398584
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-16384.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-2048.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-2048.apk
new file mode 100644
index 0000000..bf8150d
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-2048.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-3072.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-3072.apk
new file mode 100644
index 0000000..ca11ebb
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-3072.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-4096.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-4096.apk
new file mode 100644
index 0000000..dfa1206
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-4096.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-8192.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-8192.apk
new file mode 100644
index 0000000..1bdd017
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-with-rsa-pss-sha512-8192.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-only-wrong-apk-sig-block-magic.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-wrong-apk-sig-block-magic.apk
new file mode 100644
index 0000000..85750d4
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-only-wrong-apk-sig-block-magic.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-stripped-with-ignorable-signing-schemes.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-stripped-with-ignorable-signing-schemes.apk
new file mode 100644
index 0000000..634255b
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-stripped-with-ignorable-signing-schemes.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/res/pkgsigverify/v2-stripped.apk b/hostsidetests/appsecurity/res/pkgsigverify/v2-stripped.apk
new file mode 100644
index 0000000..0d04d93
--- /dev/null
+++ b/hostsidetests/appsecurity/res/pkgsigverify/v2-stripped.apk
Binary files differ
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
new file mode 100644
index 0000000..ad68017
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.appsecurity.cts;
+
+import android.appsecurity.cts.SplitTests.BaseInstallMultiple;
+
+import com.android.ddmlib.Log;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IAbiReceiver;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+/**
+ * Set of tests that verify behavior of direct boot, if supported.
+ * <p>
+ * Note that these tests drive PIN setup manually instead of relying on device
+ * administrators, which are not supported by all devices.
+ */
+public class DirectBootHostTest extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
+    private static final String TAG = "DirectBootHostTest";
+
+    private static final String PKG = "com.android.cts.encryptionapp";
+    private static final String CLASS = ".EncryptionAppTest";
+    private static final String APK = "CtsEncryptionApp.apk";
+
+    private static final String OTHER_APK = "CtsSplitApp.apk";
+    private static final String OTHER_PKG = "com.android.cts.splitapp";
+    private static final String OTHER_CLASS = ".SplitAppTest";
+
+    private static final String MODE_NATIVE = "native";
+    private static final String MODE_EMULATED = "emulated";
+    private static final String MODE_NONE = "none";
+
+    private IAbi mAbi;
+    private IBuildInfo mCtsBuild;
+
+    @Override
+    public void setAbi(IAbi abi) {
+        mAbi = abi;
+    }
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mCtsBuild = buildInfo;
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        assertNotNull(mAbi);
+        assertNotNull(mCtsBuild);
+
+        getDevice().uninstallPackage(PKG);
+        getDevice().uninstallPackage(OTHER_PKG);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+
+        getDevice().uninstallPackage(PKG);
+        getDevice().uninstallPackage(OTHER_PKG);
+    }
+
+    /**
+     * If device has native FBE, verify lifecycle.
+     */
+    public void testDirectBootNative() throws Exception {
+        if (!isSupportedDevice()) {
+            Log.v(TAG, "Device not supported; skipping test");
+            return;
+        } else if (!MODE_NATIVE.equals(getFbeMode())) {
+            Log.v(TAG, "Device doesn't have native FBE; skipping test");
+            return;
+        }
+
+        doDirectBootTest(MODE_NATIVE);
+    }
+
+    /**
+     * If device doesn't have native FBE, enable emulation and verify lifecycle.
+     */
+    public void testDirectBootEmulated() throws Exception {
+        if (!isSupportedDevice()) {
+            Log.v(TAG, "Device not supported; skipping test");
+            return;
+        } else if (MODE_NATIVE.equals(getFbeMode())) {
+            Log.v(TAG, "Device has native FBE; skipping test");
+            return;
+        }
+
+        doDirectBootTest(MODE_EMULATED);
+    }
+
+    /**
+     * If device doesn't have native FBE, verify normal lifecycle.
+     */
+    public void testDirectBootNone() throws Exception {
+        if (!isSupportedDevice()) {
+            Log.v(TAG, "Device not supported; skipping test");
+            return;
+        } else if (MODE_NATIVE.equals(getFbeMode())) {
+            Log.v(TAG, "Device has native FBE; skipping test");
+            return;
+        }
+
+        doDirectBootTest(MODE_NONE);
+    }
+
+    public void doDirectBootTest(String mode) throws Exception {
+        int[] users = {};
+        try {
+            users = createUsersForTest();
+
+            // Set up test app and secure lock screens
+            new InstallMultiple().addApk(APK).run();
+            new InstallMultiple().addApk(OTHER_APK).run();
+
+            // To receive boot broadcasts, kick our other app out of stopped state
+            getDevice().executeShellCommand("am start -a android.intent.action.MAIN"
+                    + " -c android.intent.category.LAUNCHER com.android.cts.splitapp/.MyActivity");
+
+            // Give enough time for PackageManager to persist stopped state
+            Thread.sleep(15000);
+
+            runDeviceTests(PKG, CLASS, "testSetUp", users);
+
+            // Reboot system into known state with keys ejected
+            if (MODE_EMULATED.equals(mode)) {
+                getDevice().executeShellCommand("sm set-emulate-fbe true");
+                getDevice().waitForDeviceOnline();
+            } else {
+                getDevice().rebootUntilOnline();
+            }
+            waitForBootCompleted();
+
+            if (MODE_NONE.equals(mode)) {
+                runDeviceTests(PKG, CLASS, "testVerifyUnlockedAndDismiss", users);
+            } else {
+                runDeviceTests(PKG, CLASS, "testVerifyLockedAndDismiss", users);
+            }
+
+        } finally {
+            try {
+                // Remove secure lock screens and tear down test app
+                runDeviceTests(PKG, CLASS, "testTearDown", users);
+            } finally {
+                getDevice().uninstallPackage(PKG);
+                removeUsersForTest(users);
+
+                // Get ourselves back into a known-good state
+                if (MODE_EMULATED.equals(mode)) {
+                    getDevice().executeShellCommand("sm set-emulate-fbe false");
+                    getDevice().waitForDeviceOnline();
+                } else {
+                    getDevice().nonBlockingReboot();
+                }
+                waitForBootCompleted();
+            }
+        }
+    }
+
+    private int[] createUsersForTest() throws DeviceNotAvailableException {
+        // TODO: enable test for multiple users
+        return new int[] { 0 };
+//        return Utils.createUsersForTest(getDevice());
+    }
+
+    private void removeUsersForTest(int[] users) throws DeviceNotAvailableException {
+        Utils.removeUsersForTest(getDevice(), users);
+    }
+
+    private void runDeviceTests(String packageName, String testClassName, String testMethodName,
+            int... users) throws DeviceNotAvailableException {
+        for (int user : users) {
+            Log.d(TAG, "runDeviceTests " + testMethodName + " u" + user);
+            Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName, user);
+        }
+    }
+
+    private String getFbeMode() throws Exception {
+        return getDevice().executeShellCommand("sm get-fbe-mode").trim();
+    }
+
+    private boolean isBootCompleted() throws Exception {
+        return "1".equals(getDevice().executeShellCommand("getprop sys.boot_completed").trim());
+    }
+
+    private boolean isSupportedDevice() throws Exception {
+        final String featureList = getDevice().executeShellCommand("pm list features");
+        if (featureList.contains("feature:android.hardware.type.watch\n") ||
+                featureList.contains("feature:android.hardware.type.television\n")) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    private void waitForBootCompleted() throws Exception {
+        for (int i = 0; i < 45; i++) {
+            if (isBootCompleted()) {
+                Log.d(TAG, "Yay, system is ready!");
+                return;
+            }
+            Log.d(TAG, "Waiting for system ready...");
+            Thread.sleep(1000);
+        }
+        throw new AssertionError("System failed to become ready!");
+    }
+
+    private class InstallMultiple extends BaseInstallMultiple<InstallMultiple> {
+        public InstallMultiple() {
+            super(getDevice(), mCtsBuild, mAbi);
+        }
+    }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
new file mode 100644
index 0000000..f6c6f18
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.appsecurity.cts;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Locale;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+/**
+ * Tests for APK signature verification during installation.
+ */
+public class PkgInstallSignatureVerificationTest extends DeviceTestCase implements IBuildReceiver {
+
+    private static final String TEST_PKG = "android.appsecurity.cts.tinyapp";
+    private static final String TEST_APK_RESOURCE_PREFIX = "/pkgsigverify/";
+
+    private static final String[] DSA_KEY_NAMES = {"1024", "2048", "3072"};
+    private static final String[] EC_KEY_NAMES = {"p256", "p384", "p521"};
+    private static final String[] RSA_KEY_NAMES = {"1024", "2048", "3072", "4096", "8192", "16384"};
+    private static final String[] RSA_KEY_NAMES_2048_AND_LARGER =
+            {"2048", "3072", "4096", "8192", "16384"};
+
+
+    /** Device under test. */
+    private ITestDevice mDevice;
+
+    private IBuildInfo mCtsBuild;
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mCtsBuild = buildInfo;
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mDevice = getDevice();
+        assertNotNull(mCtsBuild);
+        uninstallPackage();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        try {
+            uninstallPackage();
+        } catch (DeviceNotAvailableException ignored) {
+        } finally {
+            super.tearDown();
+        }
+    }
+
+    public void testInstallOriginalSucceeds() throws Exception {
+        // APK signed with v1 and v2 schemes. Obtained by building
+        // cts/hostsidetests/appsecurity/test-apps/tinyapp.
+        assertInstallSucceeds("original.apk");
+    }
+
+    public void testInstallV1OneSignerMD5withRSA() throws Exception {
+        // APK signed with v1 scheme only, one signer.
+        assertInstallSucceedsForEach("v1-only-with-rsa-pkcs1-md5-%s.apk", RSA_KEY_NAMES);
+    }
+
+    public void testInstallV1OneSignerSHA1withRSA() throws Exception {
+        // APK signed with v1 scheme only, one signer.
+        assertInstallSucceedsForEach("v1-only-with-rsa-pkcs1-sha1-%s.apk", RSA_KEY_NAMES);
+    }
+
+    public void testInstallV1OneSignerSHA224withRSA() throws Exception {
+        // APK signed with v1 scheme only, one signer.
+        assertInstallSucceedsForEach("v1-only-with-rsa-pkcs1-sha224-%s.apk", RSA_KEY_NAMES);
+    }
+
+    public void testInstallV1OneSignerSHA256withRSA() throws Exception {
+        // APK signed with v1 scheme only, one signer.
+        assertInstallSucceedsForEach("v1-only-with-rsa-pkcs1-sha256-%s.apk", RSA_KEY_NAMES);
+    }
+
+    public void testInstallV1OneSignerSHA384withRSA() throws Exception {
+        // APK signed with v1 scheme only, one signer.
+        assertInstallSucceedsForEach("v1-only-with-rsa-pkcs1-sha384-%s.apk", RSA_KEY_NAMES);
+    }
+
+    public void testInstallV1OneSignerSHA512withRSA() throws Exception {
+        // APK signed with v1 scheme only, one signer.
+        assertInstallSucceedsForEach("v1-only-with-rsa-pkcs1-sha512-%s.apk", RSA_KEY_NAMES);
+    }
+
+    public void testInstallV1OneSignerSHA1withECDSA() throws Exception {
+        // APK signed with v1 scheme only, one signer.
+        assertInstallSucceedsForEach("v1-only-with-ecdsa-sha1-%s.apk", EC_KEY_NAMES);
+    }
+
+    public void testInstallV1OneSignerSHA224withECDSA() throws Exception {
+        // APK signed with v1 scheme only, one signer.
+        assertInstallSucceedsForEach("v1-only-with-ecdsa-sha224-%s.apk", EC_KEY_NAMES);
+    }
+
+    public void testInstallV1OneSignerSHA256withECDSA() throws Exception {
+        // APK signed with v1 scheme only, one signer.
+        assertInstallSucceedsForEach("v1-only-with-ecdsa-sha256-%s.apk", EC_KEY_NAMES);
+    }
+
+    public void testInstallV1OneSignerSHA384withECDSA() throws Exception {
+        // APK signed with v1 scheme only, one signer.
+        assertInstallSucceedsForEach("v1-only-with-ecdsa-sha384-%s.apk", EC_KEY_NAMES);
+    }
+
+    public void testInstallV1OneSignerSHA512withECDSA() throws Exception {
+        // APK signed with v1 scheme only, one signer.
+        assertInstallSucceedsForEach("v1-only-with-ecdsa-sha512-%s.apk", EC_KEY_NAMES);
+    }
+
+    public void testInstallV1OneSignerSHA1withDSA() throws Exception {
+        // APK signed with v1 scheme only, one signer.
+        assertInstallSucceedsForEach("v1-only-with-dsa-sha1-%s.apk", DSA_KEY_NAMES);
+    }
+
+    public void testInstallV1OneSignerSHA224withDSA() throws Exception {
+        // APK signed with v1 scheme only, one signer.
+        assertInstallSucceedsForEach("v1-only-with-dsa-sha224-%s.apk", DSA_KEY_NAMES);
+    }
+
+    public void testInstallV1OneSignerSHA256withDSA() throws Exception {
+        // APK signed with v1 scheme only, one signer.
+        assertInstallSucceedsForEach("v1-only-with-dsa-sha256-%s.apk", DSA_KEY_NAMES);
+    }
+
+//  Android platform doesn't support DSA with SHA-384 and SHA-512.
+//    public void testInstallV1OneSignerSHA384withDSA() throws Exception {
+//        // APK signed with v1 scheme only, one signer.
+//        assertInstallSucceedsForEach("v1-only-with-dsa-sha384-%s.apk", DSA_KEY_NAMES);
+//    }
+//
+//    public void testInstallV1OneSignerSHA512withDSA() throws Exception {
+//        // APK signed with v1 scheme only, one signer.
+//        assertInstallSucceedsForEach("v1-only-with-dsa-sha512-%s.apk", DSA_KEY_NAMES);
+//    }
+
+    public void testInstallV2StrippedFails() throws Exception {
+        // APK signed with v1 and v2 schemes, but v2 signature was stripped from the file (by using
+        // zipalign).
+        // This should fail because the v1 signature indicates that the APK was supposed to be
+        // signed with v2 scheme as well, making the platform's anti-stripping protections reject
+        // the APK.
+        assertInstallFailsWithError("v2-stripped.apk", "Signature stripped");
+
+        // Similar to above, but the X-Android-APK-Signed anti-stripping header in v1 signature
+        // lists unknown signature schemes in addition to APK Signature Scheme v2. Unknown schemes
+        // should be ignored.
+        assertInstallFailsWithError(
+                "v2-stripped-with-ignorable-signing-schemes.apk", "Signature stripped");
+    }
+
+    public void testInstallV2OneSignerOneSignature() throws Exception {
+        // APK signed with v2 scheme only, one signer, one signature.
+        assertInstallSucceedsForEach("v2-only-with-dsa-sha256-%s.apk", DSA_KEY_NAMES);
+        assertInstallSucceedsForEach("v2-only-with-ecdsa-sha256-%s.apk", EC_KEY_NAMES);
+        assertInstallSucceedsForEach("v2-only-with-rsa-pkcs1-sha256-%s.apk", RSA_KEY_NAMES);
+        assertInstallSucceedsForEach("v2-only-with-rsa-pss-sha256-%s.apk", RSA_KEY_NAMES);
+
+        // DSA with SHA-512 is not supported by Android platform and thus APK Signature Scheme v2
+        // does not support that either
+        // assertInstallSucceedsForEach("v2-only-with-dsa-sha512-%s.apk", DSA_KEY_NAMES);
+        assertInstallSucceedsForEach("v2-only-with-ecdsa-sha512-%s.apk", EC_KEY_NAMES);
+        assertInstallSucceedsForEach("v2-only-with-rsa-pkcs1-sha512-%s.apk", RSA_KEY_NAMES);
+        assertInstallSucceedsForEach(
+                "v2-only-with-rsa-pss-sha512-%s.apk",
+                RSA_KEY_NAMES_2048_AND_LARGER // 1024-bit key is too short for PSS with SHA-512
+                );
+    }
+
+    public void testInstallV2SignatureDoesNotVerify() throws Exception {
+        // APK signed with v2 scheme only, but the signature over signed-data does not verify.
+        String error = "signature did not verify";
+
+        // Bitflip in certificate field inside signed-data. Based on
+        // v2-only-with-dsa-sha256-1024.apk.
+        assertInstallFailsWithError("v2-only-with-dsa-sha256-1024-sig-does-not-verify.apk", error);
+
+        // Signature claims to be RSA PKCS#1 v1.5 with SHA-256, but is actually using SHA-512.
+        // Based on v2-only-with-rsa-pkcs1-sha256-2048.apk.
+        assertInstallFailsWithError(
+                "v2-only-with-rsa-pkcs1-sha256-2048-sig-does-not-verify.apk", error);
+
+        // Signature claims to be RSA PSS with SHA-256 and 32 bytes of salt, but is actually using 0
+        // bytes of salt. Based on v2-only-with-rsa-pkcs1-sha256-2048.apk. Obtained by modifying APK
+        // signer to use the wrong amount of salt.
+        assertInstallFailsWithError(
+                "v2-only-with-rsa-pss-sha256-2048-sig-does-not-verify.apk", error);
+
+        // Bitflip in the ECDSA signature. Based on v2-only-with-ecdsa-sha256-p256.apk.
+        assertInstallFailsWithError(
+                "v2-only-with-ecdsa-sha256-p256-sig-does-not-verify.apk", error);
+    }
+
+    public void testInstallV2ContentDigestMismatch() throws Exception {
+        // APK signed with v2 scheme only, but the digest of contents does not match the digest
+        // stored in signed-data.
+        String error = "digest of contents did not verify";
+
+        // Based on v2-only-with-rsa-pkcs1-sha512-4096.apk. Obtained by modifying APK signer to
+        // flip the leftmost bit in content digest before signing signed-data.
+        assertInstallFailsWithError(
+                "v2-only-with-rsa-pkcs1-sha512-4096-digest-mismatch.apk", error);
+
+        // Based on v2-only-with-ecdsa-sha256-p256.apk. Obtained by modifying APK signer to flip the
+        // leftmost bit in content digest before signing signed-data.
+        assertInstallFailsWithError(
+                "v2-only-with-ecdsa-sha256-p256-digest-mismatch.apk", error);
+    }
+
+    public void testInstallNoApkSignatureSchemeBlock() throws Exception {
+        // APK signed with v2 scheme only, but the rules for verifying APK Signature Scheme v2
+        // signatures say that this APK must not be verified using APK Signature Scheme v2.
+
+        // Obtained from v2-only-with-rsa-pkcs1-sha512-4096.apk by flipping a bit in the magic
+        // field in the footer of APK Signing Block. This makes the APK Signing Block disappear.
+        assertInstallFails("v2-only-wrong-apk-sig-block-magic.apk");
+
+        // Obtained by modifying APK signer to insert "GARBAGE" between ZIP Central Directory and
+        // End of Central Directory. The APK is otherwise fine and is signed with APK Signature
+        // Scheme v2. Based on v2-only-with-rsa-pkcs1-sha256.apk.
+        assertInstallFails("v2-only-garbage-between-cd-and-eocd.apk");
+
+        // Obtained by modifying APK signer to truncate the ZIP Central Directory by one byte. The
+        // APK is otherwise fine and is signed with APK Signature Scheme v2. Based on
+        // v2-only-with-rsa-pkcs1-sha256.apk
+        assertInstallFails("v2-only-truncated-cd.apk");
+
+        // Obtained by modifying the size in APK Signature Block header. Based on
+        // v2-only-with-ecdsa-sha512-p521.apk.
+        assertInstallFails("v2-only-apk-sig-block-size-mismatch.apk");
+
+        // Obtained by modifying the ID under which APK Signature Scheme v2 Block is stored in
+        // APK Signing Block and by modifying the APK signer to not insert anti-stripping
+        // protections into JAR Signature. The APK should appear as having no APK Signature Scheme
+        // v2 Block and should thus successfully verify using JAR Signature Scheme.
+        assertInstallSucceeds("v1-with-apk-sig-block-but-without-apk-sig-scheme-v2-block.apk");
+    }
+
+    public void testInstallV2UnknownPairIgnoredInApkSigningBlock() throws Exception {
+        // Obtained by modifying APK signer to emit an unknown ID-value pair into APK Signing Block
+        // before the ID-value pair containing the APK Signature Scheme v2 Block. The unknown
+        // ID-value should be ignored.
+        assertInstallSucceeds("v2-only-unknown-pair-in-apk-sig-block.apk");
+    }
+
+    public void testInstallV2IgnoresUnknownSignatureAlgorithms() throws Exception {
+        // APK is signed with a known signature algorithm and with a couple of unknown ones.
+        // Obtained by modifying APK signer to use "unknown" signature algorithms in addition to
+        // known ones.
+        assertInstallSucceeds("v2-only-with-ignorable-unsupported-sig-algs.apk");
+    }
+
+    public void testInstallV2RejectsMismatchBetweenSignaturesAndDigestsBlocks() throws Exception {
+        // APK is signed with a single signature algorithm, but the digests block claims that it is
+        // signed with two different signature algorithms. Obtained by modifying APK Signer to
+        // emit an additional digest record with signature algorithm 0x12345678.
+        assertInstallFailsWithError(
+                "v2-only-signatures-and-digests-block-mismatch.apk",
+                "Signature algorithms don't match between digests and signatures records");
+    }
+
+    public void testInstallV2RejectsMismatchBetweenPublicKeyAndCertificate() throws Exception {
+        // APK is signed with v2 only. The public key field does not match the public key in the
+        // leaf certificate. Obtained by modifying APK signer to write out a modified leaf
+        // certificate where the RSA modulus has a bitflip.
+        assertInstallFailsWithError(
+                "v2-only-cert-and-public-key-mismatch.apk",
+                "Public key mismatch between certificate and signature record");
+    }
+
+    public void testInstallV2RejectsSignerBlockWithNoCertificates() throws Exception {
+        // APK is signed with v2 only. There are no certificates listed in the signer block.
+        // Obtained by modifying APK signer to output no certificates.
+        assertInstallFailsWithError("v2-only-no-certs-in-sig.apk", "No certificates listed");
+    }
+
+    public void testInstallTwoSigners() throws Exception {
+        // APK signed by two different signers.
+        assertInstallSucceeds("two-signers.apk");
+        // Because the install attempt below is an update, it also tests that the signing
+        // certificates exposed by v2 signatures above are the same as the one exposed by v1
+        // signatures in this APK.
+        assertInstallSucceeds("v1-only-two-signers.apk");
+        assertInstallSucceeds("v2-only-two-signers.apk");
+    }
+
+    public void testInstallV2TwoSignersRejectsWhenOneBroken() throws Exception {
+        // Bitflip in the ECDSA signature of second signer. Based on two-signers.apk.
+        // This asserts that breakage in any signer leads to rejection of the APK.
+        assertInstallFailsWithError(
+                "two-signers-second-signer-v2-broken.apk", "signature did not verify");
+    }
+
+    public void testInstallV2RejectsWhenMissingCode() throws Exception {
+        // Obtained by removing classes.dex from original.apk and then signing with v2 only.
+        // Although this has nothing to do with v2 signature verification, package manager wants
+        // signature verification / certificate collection to reject APKs with missing code
+        // (classes.dex) unless requested otherwise.
+        assertInstallFailsWithError("v2-only-missing-classes.dex.apk", "code is missing");
+    }
+
+    private void assertInstallSucceeds(String apkFilenameInResources) throws Exception {
+        String installResult = installPackageFromResource(apkFilenameInResources);
+        if (installResult != null) {
+            fail("Failed to install " + apkFilenameInResources + ": " + installResult);
+        }
+    }
+
+    private void assertInstallSucceedsForEach(
+            String apkFilenamePatternInResources, String[] args) throws Exception {
+        for (String arg : args) {
+            String apkFilenameInResources =
+                    String.format(Locale.US, apkFilenamePatternInResources, arg);
+            String installResult = installPackageFromResource(apkFilenameInResources);
+            if (installResult != null) {
+                fail("Failed to install " + apkFilenameInResources + ": " + installResult);
+            }
+            try {
+                uninstallPackage();
+            } catch (Exception e) {
+                throw new RuntimeException(
+                        "Failed to uninstall after installing " + apkFilenameInResources, e);
+            }
+        }
+    }
+
+    private void assertInstallFailsWithError(
+            String apkFilenameInResources, String errorSubstring) throws Exception {
+        String installResult = installPackageFromResource(apkFilenameInResources);
+        if (installResult == null) {
+            fail("Install of " + apkFilenameInResources + " succeeded but was expected to fail"
+                    + " with \"" + errorSubstring + "\"");
+        }
+        assertContains(
+                "Install failure message of " + apkFilenameInResources,
+                errorSubstring,
+                installResult);
+    }
+
+    private void assertInstallFails(String apkFilenameInResources) throws Exception {
+        String installResult = installPackageFromResource(apkFilenameInResources);
+        if (installResult == null) {
+            fail("Install of " + apkFilenameInResources + " succeeded but was expected to fail");
+        }
+    }
+
+    private static void assertContains(String message, String expectedSubstring, String actual) {
+        String errorPrefix = ((message != null) && (message.length() > 0)) ? (message + ": ") : "";
+        if (actual == null) {
+            fail(errorPrefix + "Expected to contain \"" + expectedSubstring + "\", but was null");
+        }
+        if (!actual.contains(expectedSubstring)) {
+            fail(errorPrefix + "Expected to contain \"" + expectedSubstring + "\", but was \""
+                    + actual + "\"");
+        }
+    }
+
+    private String installPackageFromResource(String apkFilenameInResources)
+            throws IOException, DeviceNotAvailableException {
+        // ITestDevice.installPackage API requires the APK to be install to be a File. We thus
+        // copy the requested resource into a temporary file, attempt to install it, and delete the
+        // file during cleanup.
+
+        String fullResourceName = TEST_APK_RESOURCE_PREFIX + apkFilenameInResources;
+        File apkFile = File.createTempFile("pkginstalltest", ".apk");
+        try {
+            try (InputStream in = getClass().getResourceAsStream(fullResourceName);
+                    OutputStream out = new BufferedOutputStream(new FileOutputStream(apkFile))) {
+                if (in == null) {
+                    throw new IllegalArgumentException("Resource not found: " + fullResourceName);
+                }
+                byte[] buf = new byte[65536];
+                int chunkSize;
+                while ((chunkSize = in.read(buf)) != -1) {
+                    out.write(buf, 0, chunkSize);
+                }
+            }
+            return mDevice.installPackage(apkFile, true);
+        } finally {
+            apkFile.delete();
+        }
+    }
+
+    private String uninstallPackage() throws DeviceNotAvailableException {
+        return mDevice.uninstallPackage(TEST_PKG);
+    }
+}
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/Android.mk b/hostsidetests/appsecurity/test-apps/EncryptionApp/Android.mk
index ffa96e8..d362ed6 100644
--- a/hostsidetests/appsecurity/test-apps/EncryptionApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SDK_VERSION := current
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ctsdeviceutil ctstestrunner ub-uiautomator
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/EncryptionApp/AndroidManifest.xml
index b42414c..da3c9e4 100644
--- a/hostsidetests/appsecurity/test-apps/EncryptionApp/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/AndroidManifest.xml
@@ -16,37 +16,68 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.cts.encryptionapp">
-
     <application android:label="EncryptionApp">
         <activity android:name=".UnawareActivity"
-                android:exported="true"/>
+                android:exported="true">
+            <intent-filter>
+                <action android:name="com.android.cts.encryptionapp.TEST" />
+            </intent-filter>
+        </activity>
 
         <receiver android:name=".UnawareReceiver"
-                android:exported="true" />
+                android:exported="true">
+            <intent-filter>
+                <action android:name="com.android.cts.encryptionapp.TEST" />
+            </intent-filter>
+        </receiver>
 
         <service android:name=".UnawareService"
-                android:exported="true" />
+                android:exported="true">
+            <intent-filter>
+                <action android:name="com.android.cts.encryptionapp.TEST" />
+            </intent-filter>
+        </service>
 
         <provider android:name=".UnawareProvider"
                 android:authorities="com.android.cts.encryptionapp.unaware"
-                android:exported="true" />
+                android:exported="true">
+            <intent-filter>
+                <action android:name="com.android.cts.encryptionapp.TEST" />
+            </intent-filter>
+        </provider>
 
         <activity android:name=".AwareActivity"
                 android:directBootAware="true"
-                android:exported="true" />
+                android:exported="true">
+            <intent-filter>
+                <action android:name="com.android.cts.encryptionapp.TEST" />
+            </intent-filter>
+        </activity>
 
         <receiver android:name=".AwareReceiver"
                 android:directBootAware="true"
-                android:exported="true" />
+                android:exported="true">
+            <intent-filter>
+                <action android:name="com.android.cts.encryptionapp.TEST" />
+            </intent-filter>
+        </receiver>
 
         <service android:name=".AwareService"
                 android:directBootAware="true"
-                android:exported="true" />
+                android:exported="true">
+            <intent-filter>
+                <action android:name="com.android.cts.encryptionapp.TEST" />
+            </intent-filter>
+        </service>
 
         <provider android:name=".AwareProvider"
                 android:authorities="com.android.cts.encryptionapp.aware"
                 android:directBootAware="true"
-                android:exported="true" />
+                android:exported="true">
+            <intent-filter>
+                <action android:name="com.android.cts.encryptionapp.TEST" />
+            </intent-filter>
+        </provider>
 
         <uses-library android:name="android.test.runner" />
     </application>
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/AwareActivity.java b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/AwareActivity.java
index a312a5b..617fa1f 100644
--- a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/AwareActivity.java
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/AwareActivity.java
@@ -21,11 +21,16 @@
 import android.app.Activity;
 import android.os.Bundle;
 import android.util.Log;
+import android.view.WindowManager;
 
 public class AwareActivity extends Activity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         Log.v(AWARE, "Activity.onCreate()");
+
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
     }
 }
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/AwareProvider.java b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/AwareProvider.java
index e8807cd..a95fa7d 100644
--- a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/AwareProvider.java
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/AwareProvider.java
@@ -25,9 +25,12 @@
 import android.util.Log;
 
 public class AwareProvider extends ContentProvider {
+    public static volatile boolean sCreated = false;
+
     @Override
     public boolean onCreate() {
         Log.v(AWARE, "ContentProvider.onCreate()");
+        sCreated = true;
         return true;
     }
 
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java
index 1e161f8..fd7dac7 100644
--- a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java
@@ -16,8 +16,369 @@
 
 package com.android.cts.encryptionapp;
 
-import android.test.AndroidTestCase;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
 
-public class EncryptionAppTest extends AndroidTestCase {
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ComponentInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.SystemClock;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiSelector;
+import android.test.InstrumentationTestCase;
+import android.text.format.DateUtils;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import java.io.File;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class EncryptionAppTest extends InstrumentationTestCase {
     private static final String TAG = "EncryptionAppTest";
+
+    private static final long TIMEOUT = 10 * DateUtils.SECOND_IN_MILLIS;
+
+    private static final String KEY_BOOT = "boot";
+
+    private static final String TEST_PKG = "com.android.cts.encryptionapp";
+    private static final String TEST_ACTION = "com.android.cts.encryptionapp.TEST";
+
+    private static final String OTHER_PKG = "com.android.cts.splitapp";
+
+    private Context mCe;
+    private Context mDe;
+    private PackageManager mPm;
+
+    private UiDevice mDevice;
+    private AwareActivity mActivity;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        mCe = getInstrumentation().getContext();
+        mDe = mCe.createDeviceProtectedStorageContext();
+        mPm = mCe.getPackageManager();
+
+        mDevice = UiDevice.getInstance(getInstrumentation());
+        assertNotNull(mDevice);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+
+        if (mActivity != null) {
+            mActivity.finish();
+        }
+    }
+
+    public void testSetUp() throws Exception {
+        // Write both CE/DE data for ourselves
+        assertTrue("CE file", getTestFile(mCe).createNewFile());
+        assertTrue("DE file", getTestFile(mDe).createNewFile());
+
+        doBootCountBefore();
+
+        mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
+                AwareActivity.class, null);
+        mDevice.waitForIdle();
+
+        // Set a PIN for this user
+        final Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
+        intent.addCategory(Intent.CATEGORY_DEFAULT);
+        mActivity.startActivity(intent);
+        mDevice.waitForIdle();
+
+        // Pick PIN from the option list
+        UiObject view = new UiObject(new UiSelector()
+                .resourceId("com.android.settings:id/lock_pin"));
+        assertTrue("lock_pin", view.waitForExists(TIMEOUT));
+        view.click();
+        mDevice.waitForIdle();
+
+        // Ignore any interstitial options
+        view = new UiObject(new UiSelector()
+                .resourceId("com.android.settings:id/encrypt_dont_require_password"));
+        if (view.waitForExists(TIMEOUT)) {
+            view.click();
+            mDevice.waitForIdle();
+        }
+
+        // Set our PIN
+        view = new UiObject(new UiSelector()
+                .resourceId("com.android.settings:id/password_entry"));
+        assertTrue("password_entry", view.waitForExists(TIMEOUT));
+
+        // Enter it twice to confirm
+        enterTestPin();
+        enterTestPin();
+
+        mDevice.pressBack();
+    }
+
+    public void testTearDown() throws Exception {
+        // Just in case, always try tearing down keyguard
+        dismissKeyguard();
+
+        mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
+                AwareActivity.class, null);
+        mDevice.waitForIdle();
+
+        // Clear PIN for this user
+        final Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
+        intent.addCategory(Intent.CATEGORY_DEFAULT);
+        mActivity.startActivity(intent);
+        mDevice.waitForIdle();
+
+        // Enter current PIN
+        UiObject view = new UiObject(new UiSelector()
+                .resourceId("com.android.settings:id/password_entry"));
+        assertTrue("password_entry", view.waitForExists(TIMEOUT));
+
+        enterTestPin();
+
+        // Set back to "none"
+        view = new UiObject(new UiSelector()
+                .resourceId("com.android.settings:id/lock_none"));
+        assertTrue("lock_none", view.waitForExists(TIMEOUT));
+        view.click();
+        mDevice.waitForIdle();
+
+        // Yes, we really want to
+        view = new UiObject(new UiSelector()
+                .resourceId("android:id/button1"));
+        if (view.waitForExists(TIMEOUT)) {
+            view.click();
+            mDevice.waitForIdle();
+        }
+
+        mDevice.pressBack();
+    }
+
+    public void doBootCountBefore() throws Exception {
+        final int thisCount = getBootCount();
+        mDe.getSharedPreferences(KEY_BOOT, 0).edit().putInt(KEY_BOOT, thisCount).commit();
+    }
+
+    public void doBootCountAfter() throws Exception {
+        final int lastCount = mDe.getSharedPreferences(KEY_BOOT, 0).getInt(KEY_BOOT, -1);
+        final int thisCount = getBootCount();
+        assertTrue("Current boot count " + thisCount + " not greater than last " + lastCount,
+                thisCount > lastCount);
+    }
+
+    public void testVerifyUnlockedAndDismiss() throws Exception {
+        doBootCountAfter();
+        assertUnlocked();
+        dismissKeyguard();
+        assertUnlocked();
+    }
+
+    public void testVerifyLockedAndDismiss() throws Exception {
+        doBootCountAfter();
+        assertLocked();
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final BroadcastReceiver receiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                latch.countDown();
+            }
+        };
+        mDe.registerReceiver(receiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));
+
+        dismissKeyguard();
+
+        // Dismiss keyguard should have kicked off immediate broadcast
+        assertTrue("USER_UNLOCKED", latch.await(1, TimeUnit.MINUTES));
+
+        // And we should now be fully unlocked; we run immediately like this to
+        // avoid missing BOOT_COMPLETED due to instrumentation being torn down.
+        assertUnlocked();
+    }
+
+    private void enterTestPin() throws Exception {
+        // TODO: change the combination on my luggage
+        mDevice.waitForIdle();
+        mDevice.pressKeyCode(KeyEvent.KEYCODE_1);
+        mDevice.pressKeyCode(KeyEvent.KEYCODE_2);
+        mDevice.pressKeyCode(KeyEvent.KEYCODE_3);
+        mDevice.pressKeyCode(KeyEvent.KEYCODE_4);
+        mDevice.pressKeyCode(KeyEvent.KEYCODE_5);
+        mDevice.waitForIdle();
+        mDevice.pressEnter();
+        mDevice.waitForIdle();
+    }
+
+    private void dismissKeyguard() throws Exception {
+        mDevice.wakeUp();
+        mDevice.waitForIdle();
+        mDevice.pressMenu();
+        mDevice.waitForIdle();
+        enterTestPin();
+    }
+
+    public void assertLocked() throws Exception {
+        awaitBroadcast(Intent.ACTION_LOCKED_BOOT_COMPLETED);
+
+        assertFalse("CE exists", getTestFile(mCe).exists());
+        assertTrue("DE exists", getTestFile(mDe).exists());
+
+        assertFalse("isUserUnlocked", mCe.getSystemService(UserManager.class).isUserUnlocked());
+        assertFalse("isUserUnlocked", mDe.getSystemService(UserManager.class).isUserUnlocked());
+
+        assertTrue("AwareProvider", AwareProvider.sCreated);
+        assertFalse("UnawareProvider", UnawareProvider.sCreated);
+
+        assertNotNull("AwareProvider",
+                mPm.resolveContentProvider("com.android.cts.encryptionapp.aware", 0));
+        assertNull("UnawareProvider",
+                mPm.resolveContentProvider("com.android.cts.encryptionapp.unaware", 0));
+
+        assertGetAware(true, 0);
+        assertGetAware(true, MATCH_DIRECT_BOOT_AWARE);
+        assertGetAware(false, MATCH_DIRECT_BOOT_UNAWARE);
+        assertGetAware(true, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
+
+        assertGetUnaware(false, 0);
+        assertGetUnaware(false, MATCH_DIRECT_BOOT_AWARE);
+        assertGetUnaware(true, MATCH_DIRECT_BOOT_UNAWARE);
+        assertGetUnaware(true, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
+
+        assertQuery(1, 0);
+        assertQuery(1, MATCH_DIRECT_BOOT_AWARE);
+        assertQuery(1, MATCH_DIRECT_BOOT_UNAWARE);
+        assertQuery(2, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
+    }
+
+    public void assertUnlocked() throws Exception {
+        awaitBroadcast(Intent.ACTION_LOCKED_BOOT_COMPLETED);
+        awaitBroadcast(Intent.ACTION_BOOT_COMPLETED);
+
+        assertTrue("CE exists", getTestFile(mCe).exists());
+        assertTrue("DE exists", getTestFile(mDe).exists());
+
+        assertTrue("isUserUnlocked", mCe.getSystemService(UserManager.class).isUserUnlocked());
+        assertTrue("isUserUnlocked", mDe.getSystemService(UserManager.class).isUserUnlocked());
+
+        assertTrue("AwareProvider", AwareProvider.sCreated);
+        assertTrue("UnawareProvider", UnawareProvider.sCreated);
+
+        assertNotNull("AwareProvider",
+                mPm.resolveContentProvider("com.android.cts.encryptionapp.aware", 0));
+        assertNotNull("UnawareProvider",
+                mPm.resolveContentProvider("com.android.cts.encryptionapp.unaware", 0));
+
+        assertGetAware(true, 0);
+        assertGetAware(true, MATCH_DIRECT_BOOT_AWARE);
+        assertGetAware(false, MATCH_DIRECT_BOOT_UNAWARE);
+        assertGetAware(true, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
+
+        assertGetUnaware(true, 0);
+        assertGetUnaware(false, MATCH_DIRECT_BOOT_AWARE);
+        assertGetUnaware(true, MATCH_DIRECT_BOOT_UNAWARE);
+        assertGetUnaware(true, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
+
+        assertQuery(2, 0);
+        assertQuery(1, MATCH_DIRECT_BOOT_AWARE);
+        assertQuery(1, MATCH_DIRECT_BOOT_UNAWARE);
+        assertQuery(2, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
+    }
+
+    private void assertQuery(int count, int flags) throws Exception {
+        final Intent intent = new Intent(TEST_ACTION);
+        assertEquals("activity", count, mPm.queryIntentActivities(intent, flags).size());
+        assertEquals("service", count, mPm.queryIntentServices(intent, flags).size());
+        assertEquals("provider", count, mPm.queryIntentContentProviders(intent, flags).size());
+        assertEquals("receiver", count, mPm.queryBroadcastReceivers(intent, flags).size());
+    }
+
+    private void assertGetUnaware(boolean visible, int flags) throws Exception {
+        assertGet(visible, false, flags);
+    }
+
+    private void assertGetAware(boolean visible, int flags) throws Exception {
+        assertGet(visible, true, flags);
+    }
+
+    private ComponentName buildName(String prefix, String type) {
+        return new ComponentName(TEST_PKG, TEST_PKG + "." + prefix + type);
+    }
+
+    private void assertGet(boolean visible, boolean aware, int flags) throws Exception {
+        final String prefix = aware ? "Aware" : "Unaware";
+
+        ComponentName name;
+        ComponentInfo info;
+
+        name = buildName(prefix, "Activity");
+        try {
+            info = mPm.getActivityInfo(name, flags);
+            assertTrue(name + " visible", visible);
+            assertEquals(name + " directBootAware", aware, info.directBootAware);
+        } catch (NameNotFoundException e) {
+            assertFalse(name + " visible", visible);
+        }
+
+        name = buildName(prefix, "Service");
+        try {
+            info = mPm.getServiceInfo(name, flags);
+            assertTrue(name + " visible", visible);
+            assertEquals(name + " directBootAware", aware, info.directBootAware);
+        } catch (NameNotFoundException e) {
+            assertFalse(name + " visible", visible);
+        }
+
+        name = buildName(prefix, "Provider");
+        try {
+            info = mPm.getProviderInfo(name, flags);
+            assertTrue(name + " visible", visible);
+            assertEquals(name + " directBootAware", aware, info.directBootAware);
+        } catch (NameNotFoundException e) {
+            assertFalse(name + " visible", visible);
+        }
+
+        name = buildName(prefix, "Receiver");
+        try {
+            info = mPm.getReceiverInfo(name, flags);
+            assertTrue(name + " visible", visible);
+            assertEquals(name + " directBootAware", aware, info.directBootAware);
+        } catch (NameNotFoundException e) {
+            assertFalse(name + " visible", visible);
+        }
+    }
+
+    private File getTestFile(Context context) {
+        return new File(context.getFilesDir(), "test");
+    }
+
+    private int getBootCount() throws Exception {
+        return Settings.Global.getInt(mDe.getContentResolver(), Settings.Global.BOOT_COUNT);
+    }
+
+    private void awaitBroadcast(String action) throws Exception {
+        final Context otherContext = mDe.createPackageContext(OTHER_PKG, 0)
+                .createDeviceProtectedStorageContext();
+        final File probe = new File(otherContext.getFilesDir(),
+                getBootCount() + "." + action);
+        for (int i = 0; i < 60; i++) {
+            Log.d(TAG, "Waiting for " + probe + "...");
+            if (probe.exists()) {
+                return;
+            }
+            SystemClock.sleep(1000);
+        }
+        throw new AssertionError("Failed to find " + probe);
+    }
 }
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/UnawareActivity.java b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/UnawareActivity.java
index e596741..4978023 100644
--- a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/UnawareActivity.java
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/UnawareActivity.java
@@ -21,11 +21,16 @@
 import android.app.Activity;
 import android.os.Bundle;
 import android.util.Log;
+import android.view.WindowManager;
 
 public class UnawareActivity extends Activity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         Log.v(UNAWARE, "Activity.onCreate()");
+
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
     }
 }
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/UnawareProvider.java b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/UnawareProvider.java
index 2aae88d..60d57df 100644
--- a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/UnawareProvider.java
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/UnawareProvider.java
@@ -25,9 +25,12 @@
 import android.util.Log;
 
 public class UnawareProvider extends ContentProvider {
+    public static volatile boolean sCreated = false;
+
     @Override
     public boolean onCreate() {
         Log.v(UNAWARE, "ContentProvider.onCreate()");
+        sCreated = true;
         return true;
     }
 
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
index d968863..fcf9f38 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
@@ -220,6 +220,21 @@
         return new File(dir, ".probe_" + System.nanoTime());
     }
 
+    public static File[] buildCommonChildDirs(File dir) {
+        return new File[] {
+                new File(dir, Environment.DIRECTORY_MUSIC),
+                new File(dir, Environment.DIRECTORY_PODCASTS),
+                new File(dir, Environment.DIRECTORY_ALARMS),
+                new File(dir, Environment.DIRECTORY_RINGTONES),
+                new File(dir, Environment.DIRECTORY_NOTIFICATIONS),
+                new File(dir, Environment.DIRECTORY_PICTURES),
+                new File(dir, Environment.DIRECTORY_MOVIES),
+                new File(dir, Environment.DIRECTORY_DOWNLOADS),
+                new File(dir, Environment.DIRECTORY_DCIM),
+                new File(dir, Environment.DIRECTORY_DOCUMENTS),
+        };
+    }
+
     public static void assertDirReadOnlyAccess(File path) {
         Log.d(TAG, "Asserting read-only access to " + path);
 
@@ -230,8 +245,9 @@
 
         try {
             final File probe = buildProbeFile(path);
-            probe.createNewFile();
-            probe.delete();
+            assertFalse(probe.createNewFile());
+            assertFalse(probe.exists());
+            assertFalse(probe.delete());
             fail("able to create probe!");
         } catch (IOException e) {
             // expected
@@ -248,8 +264,10 @@
 
         try {
             final File probe = buildProbeFile(path);
-            probe.createNewFile();
-            probe.delete();
+            assertTrue(probe.createNewFile());
+            assertTrue(probe.exists());
+            assertTrue(probe.delete());
+            assertFalse(probe.exists());
         } catch (IOException e) {
             fail("failed to create probe!");
         }
@@ -263,21 +281,29 @@
 
         try {
             final File probe = buildProbeFile(path);
-            probe.createNewFile();
-            probe.delete();
+            assertFalse(probe.createNewFile());
+            assertFalse(probe.exists());
+            assertFalse(probe.delete());
             fail("able to create probe!");
         } catch (IOException e) {
             // expected
         }
     }
 
+    public static void assertDirNoWriteAccess(File[] paths) {
+        for (File path : paths) {
+            assertDirNoWriteAccess(path);
+        }
+    }
+
     public static void assertDirNoWriteAccess(File path) {
         Log.d(TAG, "Asserting no write access to " + path);
 
         try {
             final File probe = buildProbeFile(path);
-            probe.createNewFile();
-            probe.delete();
+            assertFalse(probe.createNewFile());
+            assertFalse(probe.exists());
+            assertFalse(probe.delete());
             fail("able to create probe!");
         } catch (IOException e) {
             // expected
diff --git a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadExternalStorageTest.java
index 995da90..14df3cf 100644
--- a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadExternalStorageTest.java
@@ -19,6 +19,7 @@
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoWriteAccess;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadOnlyAccess;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadWriteAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.buildCommonChildDirs;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificPaths;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getMountPaths;
 
@@ -60,8 +61,13 @@
             }
 
             // Keep walking up until we leave device
-            while (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState(path))) {
-                assertDirReadOnlyAccess(path);
+            while (path != null) {
+                if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState(path))) {
+                    assertDirReadOnlyAccess(path);
+                } else {
+                    assertDirNoWriteAccess(path);
+                }
+                assertDirNoWriteAccess(buildCommonChildDirs(path));
                 path = path.getParentFile();
             }
         }
@@ -81,7 +87,9 @@
                 final File userPath = new File(path, userId);
 
                 assertDirNoWriteAccess(path);
+                assertDirNoWriteAccess(buildCommonChildDirs(path));
                 assertDirNoWriteAccess(userPath);
+                assertDirNoWriteAccess(buildCommonChildDirs(userPath));
             }
         }
     }
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/SplitApp/AndroidManifest.xml
index dba384c..d9dceb8 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/AndroidManifest.xml
@@ -18,6 +18,7 @@
         package="com.android.cts.splitapp">
 
     <uses-permission android:name="android.permission.CAMERA" />
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
 
     <application android:label="SplitApp">
         <activity android:name=".MyActivity">
@@ -33,6 +34,16 @@
                 <action android:name="android.intent.action.DATE_CHANGED" />
             </intent-filter>
         </receiver>
+        <receiver android:name=".LockedBootReceiver" android:exported="true" android:directBootAware="true">
+            <intent-filter>
+                <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
+            </intent-filter>
+        </receiver>
+        <receiver android:name=".BootReceiver" android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.BOOT_COMPLETED" />
+            </intent-filter>
+        </receiver>
 
         <uses-library android:name="android.test.runner" />
     </application>
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/BaseBootReceiver.java b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/BaseBootReceiver.java
new file mode 100644
index 0000000..1106a41
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/BaseBootReceiver.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.splitapp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.io.File;
+
+public class BaseBootReceiver extends BroadcastReceiver {
+    private static final String TAG = "SplitApp";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        try {
+            context = context.createDeviceProtectedStorageContext();
+            final File probe = new File(context.getFilesDir(),
+                    getBootCount(context) + "." + intent.getAction());
+            Log.d(TAG, "Touching probe " + probe);
+            probe.createNewFile();
+            exposeFile(probe);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static int getBootCount(Context context) throws Exception {
+        return Settings.Global.getInt(context.getContentResolver(), Settings.Global.BOOT_COUNT);
+    }
+
+    private static File exposeFile(File file) throws Exception {
+        file.setReadable(true, false);
+        file.setReadable(true, true);
+
+        File dir = file.getParentFile();
+        do {
+            dir.setExecutable(true, false);
+            dir.setExecutable(true, true);
+            dir = dir.getParentFile();
+        } while (dir != null);
+
+        return file;
+    }
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/BootReceiver.java b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/BootReceiver.java
new file mode 100644
index 0000000..150cf1d
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/BootReceiver.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.splitapp;
+
+public class BootReceiver extends BaseBootReceiver {
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/LockedBootReceiver.java b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/LockedBootReceiver.java
new file mode 100644
index 0000000..d00f1de
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/LockedBootReceiver.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.splitapp;
+
+public class LockedBootReceiver extends BaseBootReceiver {
+}
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/MyActivity.java b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/MyActivity.java
new file mode 100644
index 0000000..9b9f01c
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/src/com/android/cts/splitapp/MyActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.splitapp;
+
+import android.app.Activity;
+
+public class MyActivity extends Activity {
+}
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
index 0436252..81cf7b3 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
@@ -23,6 +23,7 @@
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoWriteAccess;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadOnlyAccess;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadWriteAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.buildCommonChildDirs;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.buildProbeFile;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.deleteContents;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificPathsExceptMedia;
@@ -229,9 +230,14 @@
                 path = path.getParentFile();
             }
 
-            // Keep walking up until we leave device
-            while (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState(path))) {
-                assertDirReadOnlyAccess(path);
+            // Walk all the way up to root
+            while (path != null) {
+                if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState(path))) {
+                    assertDirReadOnlyAccess(path);
+                } else {
+                    assertDirNoWriteAccess(path);
+                }
+                assertDirNoWriteAccess(buildCommonChildDirs(path));
                 path = path.getParentFile();
             }
         }
diff --git a/hostsidetests/appsecurity/test-apps/tinyapp/Android.mk b/hostsidetests/appsecurity/test-apps/tinyapp/Android.mk
new file mode 100644
index 0000000..15981f6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/tinyapp/Android.mk
@@ -0,0 +1,28 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SDK_VERSION := 23
+LOCAL_PACKAGE_NAME := CtsPkgInstallTinyApp
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/tinyapp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/tinyapp/AndroidManifest.xml
new file mode 100644
index 0000000..def2931
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/tinyapp/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="android.appsecurity.cts.tinyapp"
+        android:versionCode="10"
+        android:versionName="1.0">
+    <application android:label="@string/app_name">
+        <activity
+                android:name=".MainActivity"
+                android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/tinyapp/res/values/strings.xml b/hostsidetests/appsecurity/test-apps/tinyapp/res/values/strings.xml
new file mode 100644
index 0000000..70d5a95
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/tinyapp/res/values/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">Tiny App for CTS</string>
+</resources>
diff --git a/hostsidetests/appsecurity/test-apps/tinyapp/src/android/appsecurity/cts/tinyapp/MainActivity.java b/hostsidetests/appsecurity/test-apps/tinyapp/src/android/appsecurity/cts/tinyapp/MainActivity.java
new file mode 100644
index 0000000..67a7abc
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/tinyapp/src/android/appsecurity/cts/tinyapp/MainActivity.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.appsecurity.cts.tinyapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class MainActivity extends Activity {
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        finish();
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/ContactDirectoryProvider/src/com/android/cts/contactdirectoryprovider/DirectoryProvider.java b/hostsidetests/devicepolicy/app/ContactDirectoryProvider/src/com/android/cts/contactdirectoryprovider/DirectoryProvider.java
index f7ed4a8..b57a91a 100644
--- a/hostsidetests/devicepolicy/app/ContactDirectoryProvider/src/com/android/cts/contactdirectoryprovider/DirectoryProvider.java
+++ b/hostsidetests/devicepolicy/app/ContactDirectoryProvider/src/com/android/cts/contactdirectoryprovider/DirectoryProvider.java
@@ -16,6 +16,8 @@
 
 package com.android.cts.contactdirectoryprovider;
 
+import android.accounts.Account;
+import android.accounts.AccountManager;
 import android.content.ContentProvider;
 import android.content.ContentValues;
 import android.content.Context;
@@ -43,8 +45,8 @@
     private static final String CONFIG_NAME = "config";
     private static final String SET_CUSTOM_PREFIX = "set_prefix";
     private static final String AUTHORITY = "com.android.cts.contact.directory.provider";
-    private static final String TEST_ACCOUNT_NAME = "cts@android.com";
-    private static final String TEST_ACCOUNT_TYPE = "com.android.cts";
+    // Same as com.android.cts.managedprofile.AccountAuthenticator.ACCOUNT_TYPE
+    private static final String TEST_ACCOUNT_TYPE = "com.android.cts.test";
     private static final String DEFAULT_DISPLAY_NAME = "Directory";
     private static final String DEFAULT_CONTACT_NAME = "DirectoryContact";
 
@@ -109,24 +111,30 @@
         switch (match) {
             case GAL_DIRECTORIES: {
                 final MatrixCursor cursor = new MatrixCursor(projection);
-                final Object[] row = new Object[projection.length];
-                for (int i = 0; i < projection.length; i++) {
-                    final String column = projection[i];
-                    if (column.equals(Directory.ACCOUNT_NAME)) {
-                        row[i] = TEST_ACCOUNT_NAME;
-                    } else if (column.equals(Directory.ACCOUNT_TYPE)) {
-                        row[i] = TEST_ACCOUNT_TYPE;
-                    } else if (column.equals(Directory.TYPE_RESOURCE_ID)) {
-                        row[i] = R.string.directory_resource_id;
-                    } else if (column.equals(Directory.DISPLAY_NAME)) {
-                        row[i] = prefix + DEFAULT_DISPLAY_NAME;
-                    } else if (column.equals(Directory.EXPORT_SUPPORT)) {
-                        row[i] = Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY;
-                    } else if (column.equals(Directory.SHORTCUT_SUPPORT)) {
-                        row[i] = Directory.SHORTCUT_SUPPORT_NONE;
+                final AccountManager am = getContext().getSystemService(AccountManager.class);
+                Account[] accounts = am.getAccountsByType(TEST_ACCOUNT_TYPE);
+                if (accounts != null) {
+                    for (Account account : accounts) {
+                        final Object[] row = new Object[projection.length];
+                        for (int i = 0; i < projection.length; i++) {
+                            final String column = projection[i];
+                            if (column.equals(Directory.ACCOUNT_NAME)) {
+                                row[i] = account.name;
+                            } else if (column.equals(Directory.ACCOUNT_TYPE)) {
+                                row[i] = TEST_ACCOUNT_TYPE;
+                            } else if (column.equals(Directory.TYPE_RESOURCE_ID)) {
+                                row[i] = R.string.directory_resource_id;
+                            } else if (column.equals(Directory.DISPLAY_NAME)) {
+                                row[i] = prefix + DEFAULT_DISPLAY_NAME;
+                            } else if (column.equals(Directory.EXPORT_SUPPORT)) {
+                                row[i] = Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY;
+                            } else if (column.equals(Directory.SHORTCUT_SUPPORT)) {
+                                row[i] = Directory.SHORTCUT_SUPPORT_NONE;
+                            }
+                        }
+                        cursor.addRow(row);
                     }
                 }
-                cursor.addRow(row);
                 return cursor;
             }
             case GAL_FILTER:
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AlwaysOnVpnTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AlwaysOnVpnTest.java
index 8f561a6..edeefd3 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AlwaysOnVpnTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AlwaysOnVpnTest.java
@@ -68,6 +68,9 @@
     }
 
     public void testAlwaysOnVpn() throws Exception {
+        // test always-on is null by default
+        assertNull(mDevicePolicyManager.getAlwaysOnVpnPackage(ADMIN_RECEIVER_COMPONENT));
+
         final CountDownLatch vpnLatch = new CountDownLatch(1);
 
         final ConnectivityManager cm =
@@ -89,6 +92,8 @@
         cm.registerNetworkCallback(request, callback);
         try {
             mDevicePolicyManager.setAlwaysOnVpnPackage(ADMIN_RECEIVER_COMPONENT, VPN_PACKAGE);
+            assertEquals(VPN_PACKAGE, mDevicePolicyManager.getAlwaysOnVpnPackage(
+                    ADMIN_RECEIVER_COMPONENT));
             assertTrue("Took too long waiting to establish a VPN-backed connection",
                     vpnLatch.await(NETWORK_TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/HardwarePropertiesManagerTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/HardwarePropertiesManagerTest.java
index f61c796..40e5220 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/HardwarePropertiesManagerTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/HardwarePropertiesManagerTest.java
@@ -44,7 +44,7 @@
                 || temp == HardwarePropertiesManager.UNDEFINED_TEMPERATURE);
 
         // Compare current temperature and shutdown threshold.
-        assertTrue(temp < shutdownTemp
+        assertTrue(temp < shutdownTemp || temp == HardwarePropertiesManager.UNDEFINED_TEMPERATURE
                 || shutdownTemp == HardwarePropertiesManager.UNDEFINED_TEMPERATURE);
         // Compare throttling and shutdown thresholds.
         assertTrue(throttlingTemp < shutdownTemp
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/RemoteBugreportTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/RemoteBugreportTest.java
index 1c60543..efefde9 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/RemoteBugreportTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/RemoteBugreportTest.java
@@ -23,6 +23,7 @@
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObject2;
 import android.support.test.uiautomator.UiObjectNotFoundException;
 import android.support.test.uiautomator.UiSelector;
 import android.support.test.uiautomator.Until;
@@ -38,7 +39,7 @@
  */
 public class RemoteBugreportTest extends InstrumentationTestCase {
 
-    private static final int UI_TIMEOUT = 10000; //10 seconds
+    private static final int UI_TIMEOUT_MILLIS = 5000; //5 seconds
 
     private static final String MESSAGE_ONLY_ONE_MANAGED_USER_ALLOWED =
             "There should only be one user, managed by Device Owner";
@@ -61,8 +62,6 @@
                 mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
         BaseDeviceOwnerTest.assertDeviceOwner(mDevicePolicyManager);
         mComponentName = BaseDeviceOwnerTest.getWho();
-        // cancel existing notifications
-        ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE)).cancelAll();
     }
 
     /**
@@ -102,26 +101,14 @@
         if (!startedSuccessfully) {
             return;
         }
-        mUiDevice.openNotification();
 
-        // give it max 5 seconds to find the notification
-        boolean notificationPresent = mUiDevice.wait(
-                Until.hasObject(By.textStartsWith(TAKING_BUG_REPORT)), UI_TIMEOUT);
-        assertTrue(notificationPresent);
-
-        UiObject bugreportNotification = mUiDevice.findObject(
-                new UiSelector().textStartsWith(TAKING_BUG_REPORT));
+        UiObject2 bugreportNotification = findRemoteBugreportNotification();
         assertNotNull(bugreportNotification);
-        try {
-            bugreportNotification.click();
-        } catch (UiObjectNotFoundException e) {
-            throw new IllegalStateException(
-                    "Exception when clicking on 'Taking bugreport' notification", e);
-        }
+        bugreportNotification.click();
 
         // give it max 5 seconds to find the DECLINE button on the dialog
         boolean declineButtonPresent = mUiDevice.wait(
-                Until.hasObject(By.text(DECLINE)), UI_TIMEOUT);
+                Until.hasObject(By.text(DECLINE)), UI_TIMEOUT_MILLIS);
         assertTrue(declineButtonPresent);
 
         UiObject declineButton = mUiDevice.findObject(new UiSelector().text(DECLINE));
@@ -132,4 +119,28 @@
             throw new IllegalStateException("Exception when clicking on 'DECLINE' button", e);
         }
     }
+
+    /**
+     * Attempts to find the remote bugreport notification scrolling down in the notification panel
+     * in between 10 attempts.
+     */
+    private UiObject2 findRemoteBugreportNotification() {
+        mUiDevice.openNotification();
+        final int displayWidth = mUiDevice.getDisplayWidth();
+        final int displayHeight = mUiDevice.getDisplayHeight();
+        for (int i = 0; i < 10; i++) {
+            UiObject2 notification = mUiDevice.wait(Until.findObject(
+                    By.textStartsWith(TAKING_BUG_REPORT)), UI_TIMEOUT_MILLIS);
+            if (notification != null) {
+                return notification;
+            } else {
+                /* makes a swipe from the middle of the screen upwards to the top of the screen
+                (the motion is upwards, so it scrolls downwards) half a screen, so that the
+                notification is always fully visible - never cut in two pieces) */
+                mUiDevice.swipe(displayWidth / 2, displayHeight / 2, displayWidth / 2,
+                        /* endY= */ 0, /* steps= */ 30);
+            }
+        }
+        return null;
+    }
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/VrTemperatureTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/VrTemperatureTest.java
new file mode 100644
index 0000000..d3f1f2b
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/VrTemperatureTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.deviceowner;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.HardwarePropertiesManager;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.lang.Math;
+
+public class VrTemperatureTest extends BaseDeviceOwnerTest {
+    public static final int MIN_DEVICE_TEMPERATURE = -20;
+    public static final int MAX_DEVICE_TEMPERATURE = 200;
+
+    public boolean supportsVrHighPerformance() {
+        PackageManager pm = getContext().getPackageManager();
+        return pm.hasSystemFeature(PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE);
+    }
+
+    private void checkDeviceTemp(float temp, float throttlingTemp, float shutdownTemp,
+        float vrThrottlingTemp) {
+        // Compare current temperature and shutdown threshold.
+        assertTrue(temp <= shutdownTemp ||
+                shutdownTemp == HardwarePropertiesManager.UNDEFINED_TEMPERATURE);
+
+        // Compare throttling and shutdown thresholds.
+        assertTrue(throttlingTemp <= shutdownTemp ||
+                shutdownTemp == HardwarePropertiesManager.UNDEFINED_TEMPERATURE ||
+                throttlingTemp == HardwarePropertiesManager.UNDEFINED_TEMPERATURE);
+
+        // Compare VR throttling and shutdown thresholds.
+        assertTrue(vrThrottlingTemp <= MIN_DEVICE_TEMPERATURE ||
+                vrThrottlingTemp <= shutdownTemp ||
+                shutdownTemp == HardwarePropertiesManager.UNDEFINED_TEMPERATURE);
+    }
+
+    private void checkTemps(float[] temps, float[] throttlingThresholds,
+            float[] shutdownThresholds, float[] vrThrottlingThresholds) {
+        assertEquals(temps.length, throttlingThresholds.length);
+        assertEquals(temps.length, shutdownThresholds.length);
+        boolean hasVrThreshold = vrThrottlingThresholds != null &&
+                vrThrottlingThresholds.length > 0;
+        if (hasVrThreshold) {
+          assertEquals(temps.length, vrThrottlingThresholds.length);
+        }
+        for (int i = 0; i < temps.length; ++i) {
+            checkDeviceTemp(temps[i], throttlingThresholds[i], shutdownThresholds[i],
+                    !hasVrThreshold ? MIN_DEVICE_TEMPERATURE : vrThrottlingThresholds[i]);
+        }
+    }
+
+    /**
+     * Tests that temperature sensors return valid values.
+     */
+    public void testVrTemperatures() throws InterruptedException, SecurityException {
+        if (!supportsVrHighPerformance())
+            return;
+
+        HardwarePropertiesManager hm = (HardwarePropertiesManager) getContext().getSystemService(
+                Context.HARDWARE_PROPERTIES_SERVICE);
+
+        float[] cpuTemps = hm.getDeviceTemperatures(
+                HardwarePropertiesManager.DEVICE_TEMPERATURE_CPU,
+                HardwarePropertiesManager.TEMPERATURE_CURRENT);
+        float[] cpuThrottlingThresholds = hm.getDeviceTemperatures(
+                HardwarePropertiesManager.DEVICE_TEMPERATURE_CPU,
+                HardwarePropertiesManager.TEMPERATURE_THROTTLING);
+        float[] cpuShutdownThresholds = hm.getDeviceTemperatures(
+                HardwarePropertiesManager.DEVICE_TEMPERATURE_CPU,
+                HardwarePropertiesManager.TEMPERATURE_SHUTDOWN);
+
+        float[] gpuTemps = hm.getDeviceTemperatures(
+                HardwarePropertiesManager.DEVICE_TEMPERATURE_GPU,
+                HardwarePropertiesManager.TEMPERATURE_CURRENT);
+        float[] gpuThrottlingThresholds = hm.getDeviceTemperatures(
+                HardwarePropertiesManager.DEVICE_TEMPERATURE_GPU,
+                HardwarePropertiesManager.TEMPERATURE_THROTTLING);
+        float[] gpuShutdownThresholds = hm.getDeviceTemperatures(
+                HardwarePropertiesManager.DEVICE_TEMPERATURE_GPU,
+                HardwarePropertiesManager.TEMPERATURE_SHUTDOWN);
+
+        float[] batteryTemps = hm.getDeviceTemperatures(
+                HardwarePropertiesManager.DEVICE_TEMPERATURE_BATTERY,
+                HardwarePropertiesManager.TEMPERATURE_CURRENT);
+        float[] batteryThrottlingThresholds = hm.getDeviceTemperatures(
+                HardwarePropertiesManager.DEVICE_TEMPERATURE_BATTERY,
+                HardwarePropertiesManager.TEMPERATURE_THROTTLING);
+        float[] batteryShutdownThresholds = hm.getDeviceTemperatures(
+                HardwarePropertiesManager.DEVICE_TEMPERATURE_BATTERY,
+                HardwarePropertiesManager.TEMPERATURE_SHUTDOWN);
+
+        float[] skinTemps = hm.getDeviceTemperatures(
+                HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
+                HardwarePropertiesManager.TEMPERATURE_CURRENT);
+        float[] skinThrottlingThresholds = hm.getDeviceTemperatures(
+                HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
+                HardwarePropertiesManager.TEMPERATURE_THROTTLING);
+        float[] skinShutdownThresholds = hm.getDeviceTemperatures(
+                HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
+                HardwarePropertiesManager.TEMPERATURE_SHUTDOWN);
+        float[] skinVrThrottlingThresholds = hm.getDeviceTemperatures(
+                HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
+                HardwarePropertiesManager.TEMPERATURE_THROTTLING_BELOW_VR_MIN);
+
+        checkTemps(cpuTemps, cpuThrottlingThresholds, cpuShutdownThresholds, null);
+        checkTemps(gpuTemps, gpuThrottlingThresholds, gpuShutdownThresholds, null);
+        checkTemps(batteryTemps, batteryThrottlingThresholds, batteryShutdownThresholds, null);
+        checkTemps(skinTemps, skinThrottlingThresholds, skinShutdownThresholds,
+                skinVrThrottlingThresholds);
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
index 1f6bc7c..6d233b7 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
@@ -19,6 +19,7 @@
 
     <uses-sdk android:minSdkVersion="20"/>
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
     <uses-permission android:name="android.permission.READ_CONTACTS" />
@@ -99,6 +100,13 @@
                 <data android:mimeType="vnd.android.cursor.item/person" />
             </intent-filter>
         </activity>
+        <service android:name=".AccountService" android:exported="true">
+            <intent-filter>
+                <action android:name="android.accounts.AccountAuthenticator" />
+            </intent-filter>
+            <meta-data android:name="android.accounts.AccountAuthenticator"
+                       android:resource="@xml/authenticator" />
+        </service>
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/res/xml/authenticator.xml b/hostsidetests/devicepolicy/app/ManagedProfile/res/xml/authenticator.xml
new file mode 100644
index 0000000..46cbb7e
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/res/xml/authenticator.xml
@@ -0,0 +1,22 @@
+<!-- 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.
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:accountType="com.android.cts.test"
+    android:label="@string/label"
+/>
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/AccountAuthenticator.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/AccountAuthenticator.java
new file mode 100644
index 0000000..e8cc616
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/AccountAuthenticator.java
@@ -0,0 +1,100 @@
+/*
+ * 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.managedprofile;
+
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.AccountManager;
+import android.accounts.NetworkErrorException;
+import android.content.Context;
+import android.os.Bundle;
+
+/* package */ class AccountAuthenticator extends AbstractAccountAuthenticator {
+    private static AccountAuthenticator sAuthenticator = null;
+    public static final String ACCOUNT_NAME = "CTS";
+    public static final String ACCOUNT_TYPE = "com.android.cts.test";
+    private static final String AUTH_TOKEN = "authToken";
+    private static final String AUTH_TOKEN_LABEL = "authTokenLabel";
+
+    private AccountAuthenticator(Context context) {
+        super(context);
+    }
+
+    private Bundle createResultBundle() {
+        Bundle result = new Bundle();
+        result.putString(AccountManager.KEY_ACCOUNT_NAME, ACCOUNT_NAME);
+        result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE);
+        result.putString(AccountManager.KEY_AUTHTOKEN, AUTH_TOKEN);
+
+        return result;
+    }
+
+    @Override
+    public Bundle addAccount(AccountAuthenticatorResponse response, String accountType,
+            String authTokenType, String[] requiredFeatures, Bundle options)
+            throws NetworkErrorException {
+        return createResultBundle();
+    }
+
+    @Override
+    public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
+        return createResultBundle();
+    }
+
+    @Override
+    public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account,
+            String authTokenType, Bundle options) throws NetworkErrorException {
+        return createResultBundle();
+    }
+
+    @Override
+    public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account,
+            Bundle options) throws NetworkErrorException {
+
+        Bundle result = new Bundle();
+        result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
+        return result;
+    }
+
+    @Override
+    public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account,
+            String authTokenType, Bundle options) throws NetworkErrorException {
+        return createResultBundle();
+    }
+
+    @Override
+    public String getAuthTokenLabel(String authTokenType) {
+        return AUTH_TOKEN_LABEL;
+    }
+
+    @Override
+    public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account,
+            String[] features) throws NetworkErrorException {
+
+        Bundle result = new Bundle();
+        result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
+        return result;
+    }
+
+    public static synchronized AccountAuthenticator getAuthenticator(Context context) {
+        if (sAuthenticator == null) {
+            sAuthenticator = new AccountAuthenticator(context.getApplicationContext());
+        }
+        return sAuthenticator;
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/AccountService.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/AccountService.java
new file mode 100644
index 0000000..5c34a79
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/AccountService.java
@@ -0,0 +1,29 @@
+/*
+ * 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.managedprofile;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class AccountService extends Service {
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return AccountAuthenticator.getAuthenticator(this).getIBinder();
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ContactsTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ContactsTest.java
index 0c4e74c..5a2b3fa 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ContactsTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ContactsTest.java
@@ -16,6 +16,8 @@
 
 package com.android.cts.managedprofile;
 
+import android.accounts.Account;
+import android.accounts.AccountManager;
 import android.annotation.TargetApi;
 import android.app.admin.DevicePolicyManager;
 import android.content.ContentProviderOperation;
@@ -50,8 +52,8 @@
 @TargetApi(Build.VERSION_CODES.LOLLIPOP)
 public class ContactsTest extends AndroidTestCase {
 
-    private static final String TEST_ACCOUNT_NAME = "CTS";
-    private static final String TEST_ACCOUNT_TYPE = "com.android.cts.test";
+    private static final String TEST_ACCOUNT_NAME = AccountAuthenticator.ACCOUNT_NAME;
+    private static final String TEST_ACCOUNT_TYPE = AccountAuthenticator.ACCOUNT_TYPE;
     // details of a sample primary contact
     private static final String PRIMARY_CONTACT_DISPLAY_NAME = "Primary";
     private static final String PRIMARY_CONTACT_PHONE = "00000001";
@@ -140,6 +142,11 @@
                 .getSystemService(Context.DEVICE_POLICY_SERVICE);
     }
 
+    public void testAddTestAccount() {
+        Account account = new Account(TEST_ACCOUNT_NAME, TEST_ACCOUNT_TYPE);
+        AccountManager.get(getContext()).addAccountExplicitly(account, null, null);
+    }
+
     public void testPrimaryProfilePhoneAndEmailLookup_insertedAndfound() throws RemoteException,
             OperationApplicationException, NotFoundException, IOException {
         assertFalse(isManagedProfile());
@@ -1232,6 +1239,9 @@
             // Catch all exceptions to let tearDown() run smoothly
             e.printStackTrace();
         }
+
+        Account account = new Account(TEST_ACCOUNT_NAME, TEST_ACCOUNT_TYPE);
+        AccountManager.get(getContext()).removeAccountExplicitly(account);
     }
 
     private InputStream getInputStreamFromUriForTest(String uriString) {
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/WifiTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/WifiTest.java
index c4c02e8..685ad82 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/WifiTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/WifiTest.java
@@ -44,7 +44,7 @@
     private static final String NETWORK_SSID = "com.android.cts.xwde7ktvh8rmjuhr";
 
     // Time duration to allow before assuming that a WiFi operation failed and ceasing to wait.
-    private static final long UPDATE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(30);
+    private static final long UPDATE_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(5);
     private static final long UPDATE_INTERVAL_MS = TimeUnit.SECONDS.toMillis(1);
 
     // Shared WifiManager instance.
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index 2471cca..afead29 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -366,6 +366,14 @@
         executeDeviceTestMethod(".HardwarePropertiesManagerTest", "testHardwarePropertiesManager");
     }
 
+    // Execute VrTemperatureTest as a device owner.
+    public void testVrTemperaturesAsDeviceOwner() throws Exception {
+        if (!mHasFeature)
+            return;
+
+        executeDeviceTestMethod(".VrTemperatureTest", "testVrTemperatures");
+    }
+
     public void testIsManagedDeviceProvisioningAllowed() throws Exception {
         if (!mHasFeature) {
             return;
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 8eaa606..975cf4b 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -751,6 +751,12 @@
         }
 
         try {
+            // Add test account
+            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
+                    "testAddTestAccount", mParentUserId));
+            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ContactsTest",
+                    "testAddTestAccount", mProfileUserId));
+
             // Install directory provider to both primary and managed profile
             installAppAsUser(DIRECTORY_PROVIDER_APK, mProfileUserId);
             installAppAsUser(DIRECTORY_PROVIDER_APK, mParentUserId);
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index f33d434..360257a 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -244,19 +244,37 @@
     /**
      * Asserts the result of a command, wait and re-running it a couple times if necessary.
      */
-    protected void assertDelayedShellCommand(String command, String expectedResult)
+    protected void assertDelayedShellCommand(String command, final String expectedResult)
+            throws Exception {
+        assertDelayedShellCommand(command, new ExpectResultChecker() {
+
+            @Override
+            public boolean isExpected(String result) {
+                return expectedResult.equals(result);
+            }
+
+            @Override
+            public String getExpected() {
+                return expectedResult;
+            }
+        });
+    }
+
+    protected void assertDelayedShellCommand(String command, ExpectResultChecker checker)
             throws Exception {
         final int maxTries = 5;
+        String result = "";
         for (int i = 1; i <= maxTries; i++) {
-            final String result = executeShellCommand(command).trim();
-            if (result.equals(expectedResult))
-                return;
+            result = executeShellCommand(command).trim();
+            if (checker.isExpected(result)) return;
             Log.v(TAG, "Command '" + command + "' returned '" + result + " instead of '"
-                    + expectedResult + "' on attempt #" + i + "; sleeping 1s before trying again");
+                    + checker.getExpected() + "' on attempt #" + i
+                    + "; sleeping 1s before trying again");
             Thread.sleep(SECOND_IN_MS);
         }
-        fail("Command '" + command + "' did not return '" + expectedResult + "' after " + maxTries
-                + " attempts");
+        fail("Command '" + command + "' did not return '" + checker.getExpected() + "' after "
+                + maxTries
+                + " attempts. Last result: '" + result + "'");
     }
 
     protected void setMeteredNetwork() throws Exception {
@@ -265,16 +283,23 @@
         if (metered) {
             Log.d(TAG, "Active network already metered: " + info);
             return;
+        } else {
+            Log.w(TAG, "Active network not metered: " + info);
         }
         final String netId = setWifiMeteredStatus(true);
         assertTrue("Could not set wifi '" + netId + "' as metered ("
                 + mCm.getActiveNetworkInfo() +")", mCm.isActiveNetworkMetered());
         // Set flag so status is reverted on teardown.
         mResetMeteredWifi = true;
+        // Sanity check.
+        assertMeteredNetwork(netId, true);
     }
 
-    protected String setWifiMeteredStatus(boolean metered) throws Exception {
-        mWfm.setWifiEnabled(true);
+    private String setWifiMeteredStatus(boolean metered) throws Exception {
+        // We could call setWifiEnabled() here, but it might take sometime to be in a consistent
+        // state (for example, if one of the saved network is not properly authenticated), so it's
+        // better to let the hostside test take care of that.
+        assertTrue("wi-fi is disabled", mWfm.isWifiEnabled());
         // TODO: if it's not guaranteed the device has wi-fi, we need to change the tests
         // to make the actual verification of restrictions optional.
         final String ssid = mWfm.getConnectionInfo().getSSID();
@@ -286,13 +311,26 @@
         final String setCommand = "cmd netpolicy set metered-network " + netId + " " + metered;
         assertDelayedShellCommand(setCommand, "");
 
-        // Sanity check.
-        final  String getCommand = "cmd netpolicy get metered-network " + netId;
-        assertDelayedShellCommand(getCommand, Boolean.toString(metered));
-
         return netId;
     }
 
+    private void assertMeteredNetwork(String netId, boolean status) throws Exception {
+        final String command = "cmd netpolicy list wifi-networks";
+        final String expectedLine = netId + ";" + status;
+        assertDelayedShellCommand(command, new ExpectResultChecker() {
+
+            @Override
+            public boolean isExpected(String result) {
+                return result.contains(expectedLine);
+            }
+
+            @Override
+            public String getExpected() {
+                return "line containing " + expectedLine;
+            }
+        });
+    }
+
     protected void setRestrictBackground(boolean enabled) throws Exception {
         executeShellCommand("cmd netpolicy set restrict-background " + enabled);
         final String output = executeShellCommand("cmd netpolicy get restrict-background ");
@@ -445,4 +483,9 @@
             return fullState;
         }
     }
+
+    protected static interface ExpectResultChecker {
+        boolean isExpected(String result);
+        String getExpected();
+    }
 }
diff --git a/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java b/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java
index 08fb887..ab1b7d6 100644
--- a/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java
+++ b/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java
@@ -63,6 +63,8 @@
         assertNotNull(mAbi);
         assertNotNull(mCtsBuild);
 
+        assertTrue("device not connected to network", getDevice().checkConnectivity());
+
         uninstallPackage(TEST_PKG, false);
         installPackage(TEST_APK);
     }
diff --git a/hostsidetests/sample/src/android/sample/cts/SampleHostResultTest.java b/hostsidetests/sample/src/android/sample/cts/SampleHostResultTest.java
index b75ea94..808899a 100644
--- a/hostsidetests/sample/src/android/sample/cts/SampleHostResultTest.java
+++ b/hostsidetests/sample/src/android/sample/cts/SampleHostResultTest.java
@@ -132,13 +132,16 @@
         // Compute the stats.
         Stat.StatResult stat = Stat.getStat(result);
         // Get the report for this test and add the results to record.
+        String reportLogName = "SampleHostTestMetrics";
+        String streamName = "test_transfer_time_metrics";
         MetricsReportLog report = new MetricsReportLog(mDevice.getSerialNumber(), mAbi.getName(),
-                String.format("%s#testTransferTime", getClass().getCanonicalName()));
-        report.addValues("Times", result, ResultType.LOWER_BETTER, ResultUnit.MS);
-        report.addValue("Min", stat.mMin, ResultType.LOWER_BETTER, ResultUnit.MS);
-        report.addValue("Max", stat.mMax, ResultType.LOWER_BETTER, ResultUnit.MS);
+                String.format("%s#testTransferTime", getClass().getCanonicalName()),
+                reportLogName, streamName);
+        report.addValues("times", result, ResultType.LOWER_BETTER, ResultUnit.MS);
+        report.addValue("min", stat.mMin, ResultType.LOWER_BETTER, ResultUnit.MS);
+        report.addValue("max", stat.mMax, ResultType.LOWER_BETTER, ResultUnit.MS);
         // Every report must have a summary,
-        report.setSummary("Average", stat.mAverage, ResultType.LOWER_BETTER, ResultUnit.MS);
+        report.setSummary("average", stat.mAverage, ResultType.LOWER_BETTER, ResultUnit.MS);
         // Send the report to Tradefed.
         report.submit();
     }
diff --git a/hostsidetests/security/Android.mk b/hostsidetests/security/Android.mk
index 1b32669..34e0e8a 100644
--- a/hostsidetests/security/Android.mk
+++ b/hostsidetests/security/Android.mk
@@ -30,6 +30,8 @@
 
 LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
 
+LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+
 LOCAL_CTS_TEST_PACKAGE := android.host.security
 
 selinux_general_seapp_contexts := $(call intermediates-dir-for,ETC,general_seapp_contexts)/general_seapp_contexts
@@ -57,7 +59,14 @@
 
 selinux_neverallow_gen_data := cts/tools/selinux/SELinuxNeverallowTestFrame.py
 
-LOCAL_ADDITIONAL_DEPENDENCIES := $(COMPATIBILITY_TESTCASES_OUT_cts)/sepolicy-analyze
+old_cts_sepolicy-analyze := $(CTS_TESTCASES_OUT)/sepolicy-analyze
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(COMPATIBILITY_TESTCASES_OUT_cts)/sepolicy-analyze \
+    $(old_cts_sepolicy-analyze)
+
+$(old_cts_sepolicy-analyze) : $(HOST_OUT_EXECUTABLES)/sepolicy-analyze
+	mkdir -p $(dir $@)
+	$(copy-file-to-target)
 
 LOCAL_GENERATED_SOURCES := $(call local-generated-sources-dir)/android/cts/security/SELinuxNeverallowRulesTest.java
 
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index 222533a..0a26c97 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -16,7 +16,7 @@
 
 package android.security.cts;
 
-import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.cts.migration.MigrationHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.CollectingOutputReceiver;
 import com.android.tradefed.device.DeviceNotAvailableException;
@@ -66,19 +66,19 @@
     private File deviceSvcFile;
     private File seappNeverAllowFile;
 
+    private IBuildInfo mBuild;
+
     /**
      * A reference to the device under test.
      */
     private ITestDevice mDevice;
 
-    private CompatibilityBuildHelper mHelper;
-
     /**
      * {@inheritDoc}
      */
     @Override
     public void setBuild(IBuildInfo build) {
-        mHelper = new CompatibilityBuildHelper(build);
+        mBuild = build;
     }
 
     /**
@@ -107,7 +107,7 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        sepolicyAnalyze = new File(mHelper.getTestsDir(), "sepolicy-analyze");
+        sepolicyAnalyze = MigrationHelper.getTestFile(mBuild, "sepolicy-analyze");
         sepolicyAnalyze.setExecutable(true);
 
         /* obtain sepolicy file from running device */
diff --git a/hostsidetests/ui/control/AndroidManifest.xml b/hostsidetests/ui/control/AndroidManifest.xml
index fd48287..8102620 100644
--- a/hostsidetests/ui/control/AndroidManifest.xml
+++ b/hostsidetests/ui/control/AndroidManifest.xml
@@ -18,6 +18,7 @@
         package="android.taskswitching.control.cts">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/libs/runner/Android.mk b/libs/runner/Android.mk
index 9642f53..15f64a3 100644
--- a/libs/runner/Android.mk
+++ b/libs/runner/Android.mk
@@ -16,9 +16,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := $(call all-java-files-under, ../../tests/core/runner/src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := cts-test-runner
 
 LOCAL_MODULE_TAGS := optional
 
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
index bb199b4..1256546 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
@@ -205,7 +205,8 @@
         mAccessibilityManager.addAccessibilityStateChangeListener(listener);
         long timeoutTime = System.currentTimeMillis() + WAIT_FOR_ACCESSIBILITY_ENABLED_TIMEOUT;
         synchronized (waitObject) {
-            if (!mAccessibilityManager.isEnabled() && (System.currentTimeMillis() < timeoutTime)) {
+            while (!mAccessibilityManager.isEnabled()
+                    && (System.currentTimeMillis() < timeoutTime)) {
                 waitObject.wait(timeoutTime - System.currentTimeMillis());
             }
         }
@@ -227,7 +228,8 @@
         mAccessibilityManager.addTouchExplorationStateChangeListener(listener);
         long timeoutTime = System.currentTimeMillis() + WAIT_FOR_ACCESSIBILITY_ENABLED_TIMEOUT;
         synchronized (waitObject) {
-            if (!mAccessibilityManager.isEnabled() && (System.currentTimeMillis() < timeoutTime)) {
+            while (!mAccessibilityManager.isTouchExplorationEnabled()
+                    && (System.currentTimeMillis() < timeoutTime)) {
                 waitObject.wait(timeoutTime - System.currentTimeMillis());
             }
         }
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityWindowInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityWindowInfoTest.java
index 293feec..ffbe833 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityWindowInfoTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityWindowInfoTest.java
@@ -20,6 +20,7 @@
 import android.os.Parcel;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
 import android.view.accessibility.AccessibilityWindowInfo;
 
 /**
@@ -34,7 +35,7 @@
 
         AccessibilityWindowInfo w2 = AccessibilityWindowInfo.obtain(w1);
         assertNotSame(w1, w2);
-        assertEquals(w1, w2);
+        assertTrue(areWindowsEqual(w1, w2));
     }
 
     @SmallTest
@@ -45,8 +46,7 @@
         parcel.setDataPosition(0);
         AccessibilityWindowInfo w2 = AccessibilityWindowInfo.CREATOR.createFromParcel(parcel);
         assertNotSame(w1, w2);
-        assertEquals(w1, w2);
-
+        assertTrue(areWindowsEqual(w1, w2));
     }
 
     @SmallTest
@@ -62,6 +62,7 @@
         assertFalse(w.isAccessibilityFocused());
         assertFalse(w.isActive());
         assertFalse(w.isFocused());
+        assertNull(w.getTitle());
 
         Rect rect = new Rect();
         w.getBoundsInScreen(rect);
@@ -87,4 +88,19 @@
             // Expected.
         }
     }
+
+    private boolean areWindowsEqual(AccessibilityWindowInfo w1, AccessibilityWindowInfo w2) {
+        boolean equality = w1.equals(w2);
+        equality &= TextUtils.equals(w1.getTitle(), w2.getTitle());
+        equality &= w1.isAccessibilityFocused() == w2.isAccessibilityFocused();
+        equality &= w1.isActive() == w2.isActive();
+        equality &= w1.getType() == w2.getType();
+        equality &= w1.getLayer() == w2.getLayer();
+        Rect bounds1 = new Rect();
+        Rect bounds2 = new Rect();
+        w1.getBoundsInScreen(bounds1);
+        w2.getBoundsInScreen(bounds2);
+        equality &= bounds1.equals(bounds2);
+        return equality;
+    }
 }
diff --git a/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java
index 997ee61..cf82666 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java
@@ -47,11 +47,6 @@
         mUiAutomation = getInstrumentation().getUiAutomation();
     }
 
-    @Override
-    public void tearDown() {
-        mUiAutomation.destroy();
-    }
-
     /**
      * Tests whether a client can observe changes in caption properties.
      */
diff --git a/tests/accessibilityservice/AndroidManifest.xml b/tests/accessibilityservice/AndroidManifest.xml
index 1dfb5e0..3381f48 100644
--- a/tests/accessibilityservice/AndroidManifest.xml
+++ b/tests/accessibilityservice/AndroidManifest.xml
@@ -21,7 +21,7 @@
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
 
-    <application android:theme="@android:style/Theme.Material.NoActionBar">
+    <application android:theme="@android:style/Theme.Holo.NoActionBar">
 
         <uses-library android:name="android.test.runner" />
 
@@ -45,6 +45,9 @@
             android:label="@string/accessibility_text_traversal_test_activity"
             android:name=".AccessibilityTextTraversalActivity"/>
 
+        <activity android:label="Activity for testing window accessibility reporting"
+             android:name=".AccessibilityWindowReportingActivity"/>
+
         <activity
             android:label="Full screen activity for gesture dispatch testing"
             android:name=".AccessibilityGestureDispatchTest$GestureDispatchActivity" />
@@ -68,7 +71,7 @@
             android:windowSoftInputMode="stateAlwaysVisible" />
 
         <service
-            android:name=".StubSoftKeyboardModesAccessibilityService"
+            android:name=".InstrumentedAccessibilityService"
             android:label="@string/title_soft_keyboard_modes_accessibility_service"
             android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
             <intent-filter>
diff --git a/tests/accessibilityservice/res/layout/accessibility_window_reporting_test.xml b/tests/accessibilityservice/res/layout/accessibility_window_reporting_test.xml
new file mode 100644
index 0000000..074343e
--- /dev/null
+++ b/tests/accessibilityservice/res/layout/accessibility_window_reporting_test.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+    <AutoCompleteTextView
+              android:id="@+id/autoCompleteLayout"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
index 9dd40fe..d8a1be1 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
@@ -55,10 +55,6 @@
         super(AccessibilityEndToEndActivity.class);
     }
 
-    public void tearDown() {
-        getInstrumentation().getUiAutomation().destroy();
-    }
-
     @MediumTest
     public void testTypeViewSelectedAccessibilityEvent() throws Throwable {
         // create and populate the expected event
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncTest.java
index 892fbb0..ec420de 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityFocusAndInputFocusSyncTest.java
@@ -40,10 +40,6 @@
         super(AccessibilityFocusAndInputFocusSyncActivity.class);
     }
 
-    public void tearDown() {
-        getInstrumentation().getUiAutomation().destroy();
-    }
-
     @MediumTest
     public void testFindAccessibilityFocus() throws Exception {
         // Get the view that has input and accessibility focus.
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
index 2867674..7da7d37 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
@@ -29,6 +29,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Verify that gestures dispatched from an accessibility service show up in the current UI
@@ -311,6 +312,63 @@
         }
     }
 
+    public void testClickWhenMagnified_matchesActualTouch() throws InterruptedException {
+        final int clickXInsideView = 10;
+        final int clickYInsideView = 20;
+        int clickX = clickXInsideView + mViewBounds.left;
+        int clickY = clickYInsideView + mViewBounds.top;
+        final float TOUCH_TOLERANCE = 2.0f;
+
+        StubMagnificationAccessibilityService magnificationService =
+                StubMagnificationAccessibilityService.enableSelf(this);
+        android.accessibilityservice.AccessibilityService.MagnificationController
+                magnificationController = magnificationService.getMagnificationController();
+        try {
+            // Magnify screen by 2x from upper left corner
+            final AtomicBoolean setScale = new AtomicBoolean();
+            final AtomicBoolean setCenter = new AtomicBoolean();
+            final float magnificationFactor = 2.0f;
+            magnificationService.runOnServiceSync(() -> {
+                        setScale.set(magnificationController.setScale(magnificationFactor, false));
+                        setCenter.set(magnificationController.setCenter(0, 0, false));
+                    });
+            assertTrue("Failed to set scale", setScale.get());
+            assertTrue("Failed to set center", setCenter.get());
+
+            GestureDescription click = createClick((int) (clickX * magnificationFactor),
+                    (int) (clickY * magnificationFactor));
+            mService.runOnServiceSync(() -> mService.doDispatchGesture(click, mCallback, null));
+            mCallback.assertGestureCompletes(GESTURE_COMPLETION_TIMEOUT);
+            waitForMotionEvents(3);
+        } finally {
+            // Reset magnification
+            final AtomicBoolean result = new AtomicBoolean();
+            magnificationService.runOnServiceSync(() ->
+                    result.set(magnificationController.reset(false)));
+            magnificationService.runOnServiceSync(() -> magnificationService.disableSelf());
+            assertTrue("Failed to reset", result.get());
+        }
+
+        assertEquals(3, mMotionEvents.size());
+        MotionEvent clickDown = mMotionEvents.get(0);
+        MotionEvent clickMove = mMotionEvents.get(1);
+        MotionEvent clickUp = mMotionEvents.get(2);
+
+        assertEquals(MotionEvent.ACTION_DOWN, clickDown.getActionMasked());
+        assertEquals((float) clickXInsideView, clickDown.getX(), TOUCH_TOLERANCE);
+        assertEquals((float) clickYInsideView, clickDown.getY(), TOUCH_TOLERANCE);
+        assertEquals(clickDown.getDownTime(), clickDown.getEventTime());
+
+        assertEquals(MotionEvent.ACTION_MOVE, clickMove.getActionMasked());
+        assertEquals((float) clickXInsideView + 1, clickMove.getX(), TOUCH_TOLERANCE);
+        assertEquals((float) clickYInsideView, clickMove.getY(), TOUCH_TOLERANCE);
+
+        assertEquals(MotionEvent.ACTION_UP, clickUp.getActionMasked());
+        assertEquals((float) clickXInsideView + 1, clickUp.getX(), TOUCH_TOLERANCE);
+        assertEquals((float) clickYInsideView, clickUp.getY(), TOUCH_TOLERANCE);
+    }
+
+
     public static class GestureDispatchActivity extends AccessibilityTestActivity {
         public GestureDispatchActivity() {
             super();
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java
index 4eb625c..b782216e 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java
@@ -43,12 +43,6 @@
 public class AccessibilitySoftKeyboardModesTest extends ActivityInstrumentationTestCase2
         <AccessibilitySoftKeyboardModesTest.SoftKeyboardModesActivity> {
 
-    /**
-     * Timeout in which we are waiting for the system to start the mock
-     * accessibility services.
-     */
-    private static final long TIMEOUT_SERVICE_TOGGLE_MS = 10000;
-
     private static final long TIMEOUT_PROPAGATE_SETTING = 5000;
 
     /**
@@ -67,9 +61,9 @@
 
     private int mLastCallbackValue;
 
-    private Context mContext;
-    private StubSoftKeyboardModesAccessibilityService mService;
+    private InstrumentedAccessibilityService mService;
     private SoftKeyboardController mKeyboardController;
+    private UiAutomation mUiAutomation;
 
     private Object mLock = new Object();
 
@@ -85,32 +79,19 @@
         // windows on screen.
         getActivity();
 
-        mContext = getInstrumentation().getContext();
-        UiAutomation uiAutomation;
-        try {
-            uiAutomation = getUiAutomation();
-        } catch (RuntimeException e) {
-            // Clean up UI Automation after other tests as we cannot request UI Automation with
-            // different flags if one already exists.
-            uiAutomation = getInstrumentation().getUiAutomation();
-            uiAutomation.destroy();
-
-            // Try to get UI Automation again.
-            uiAutomation = getUiAutomation();
-        }
-        String command = "pm grant " + mContext.getPackageName()
-                + "android.permission.WRITE_SECURE_SETTINGS";
-        executeShellCommand(uiAutomation, command);
-        uiAutomation.destroy();
-
-        disableAllServices();
-        enableTestService();
-
+        mService = InstrumentedAccessibilityService.enableService(
+                this, InstrumentedAccessibilityService.class);
+        mKeyboardController = mService.getSoftKeyboardController();
+        mUiAutomation = getInstrumentation()
+                .getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
+        AccessibilityServiceInfo info = mUiAutomation.getServiceInfo();
+        info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
+        mUiAutomation.setServiceInfo(info);
     }
 
     @Override
     public void tearDown() throws Exception {
-        disableAllServices();
+        mService.runOnServiceSync(() -> mService.disableSelf());
     }
 
     public void testApiReturnValues_shouldChangeValueOnRequestAndSendCallback() throws Exception {
@@ -155,7 +136,7 @@
 
         // Note: This Activity always has a visible keyboard (due to windowSoftInputMode being set
         // to stateAlwaysVisible).
-        int numWindowsWithIme = mService.getTestWindowsListSize();
+        int numWindowsWithIme = mUiAutomation.getWindows().size();
 
         // Request the keyboard be hidden.
         assertTrue(mKeyboardController.setShowMode(SHOW_MODE_HIDDEN));
@@ -163,7 +144,7 @@
         waitForIdle();
 
         // Make sure the keyboard is hidden.
-        assertEquals(numWindowsWithIme - 1, mService.getTestWindowsListSize());
+        assertEquals(numWindowsWithIme - 1, mUiAutomation.getWindows().size());
 
         // Request the default keyboard mode.
         assertTrue(mKeyboardController.setShowMode(SHOW_MODE_AUTO));
@@ -171,17 +152,16 @@
         waitForIdle();
 
         // Make sure the keyboard is visible.
-        assertEquals(numWindowsWithIme, mService.getTestWindowsListSize());
+        assertEquals(numWindowsWithIme, mUiAutomation.getWindows().size());
     }
 
-
-    public void testHideSoftKeyboard_shouldHideKeyboardUntilAllServicesDisabled() throws Exception {
+    public void testHideSoftKeyboard_shouldHideKeyboardUntilServiceIsDisabled() throws Exception {
         // The soft keyboard should be in its' default mode.
         assertEquals(SHOW_MODE_AUTO, mKeyboardController.getShowMode());
 
         // Note: This Activity always has a visible keyboard (due to windowSoftInputMode being set
         // to stateAlwaysVisible).
-        int numWindowsWithIme = mService.getTestWindowsListSize();
+        int numWindowsWithIme = mUiAutomation.getWindows().size();
 
         // Set the show mode to SHOW_MODE_HIDDEN.
         assertTrue(mKeyboardController.setShowMode(SHOW_MODE_HIDDEN));
@@ -189,39 +169,15 @@
         waitForIdle();
 
         // Make sure the keyboard is hidden.
-        assertEquals(numWindowsWithIme - 1, mService.getTestWindowsListSize());
+        assertEquals(numWindowsWithIme - 1, mUiAutomation.getWindows().size());
 
         // Make sure we can see the soft keyboard once all Accessibility Services are disabled.
-        disableAllServices();
+        mService.disableSelf();
         waitForWindowStateChanged();
         waitForIdle();
 
-        // Enable our test service,.
-        enableTestService();
-
         // See how many windows are present.
-        assertEquals(numWindowsWithIme, mService.getTestWindowsListSize());
-    }
-
-    private synchronized UiAutomation getUiAutomation() {
-        return getInstrumentation()
-                .getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
-    }
-
-    private void executeShellCommand(UiAutomation uiAutomation, String command) throws Exception {
-        ParcelFileDescriptor fd = uiAutomation.executeShellCommand(command);
-        BufferedReader reader = null;
-        try (InputStream inputStream = new FileInputStream(fd.getFileDescriptor())) {
-            reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
-            while (reader.readLine() != null) {
-                // Keep reading.
-            }
-        } finally {
-            if (reader != null) {
-                reader.close();
-            }
-            fd.close();
-        }
+        assertEquals(numWindowsWithIme, mUiAutomation.getWindows().size());
     }
 
     private void waitForCallbackValueWithLock(int expectedValue) throws Exception {
@@ -245,9 +201,8 @@
     }
 
     private void waitForWindowStateChanged() throws Exception {
-        UiAutomation uiAutomation = getUiAutomation();
         try {
-            uiAutomation.executeAndWaitForEvent(new Runnable() {
+            mUiAutomation.executeAndWaitForEvent(new Runnable() {
                 @Override
                 public void run() {
                     // Do nothing.
@@ -261,95 +216,13 @@
             },
             TIMEOUT_PROPAGATE_SETTING);
         } catch (TimeoutException ignored) {
-            // Ignore since the event could have occured before this method was called. There should
-            // be a check after this method returns to catch incorrect values.
-        } finally {
-            uiAutomation.destroy();
+            // Ignore since the event could have occurred before this method was called. There
+            // should be a check after this method returns to catch incorrect values.
         }
     }
 
-    private void disableAllServices() throws Exception {
-        final Object waitLockForA11yOff = new Object();
-        AccessibilityManager manager =
-                (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
-        manager.addAccessibilityStateChangeListener(
-                new AccessibilityManager.AccessibilityStateChangeListener() {
-                    @Override
-                    public void onAccessibilityStateChanged(boolean b) {
-                        synchronized (waitLockForA11yOff) {
-                            waitLockForA11yOff.notifyAll();
-                        }
-                    }
-                });
-        ContentResolver cr = mContext.getContentResolver();
-        UiAutomation uiAutomation = getUiAutomation();
-        executeShellCommand(uiAutomation, "settings put secure "
-                + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES + " null");
-        uiAutomation.destroy();
-        StubSoftKeyboardModesAccessibilityService.sInstance = null;
-        long timeoutTimeMillis = SystemClock.uptimeMillis() + TIMEOUT_SERVICE_TOGGLE_MS;
-        while (SystemClock.uptimeMillis() < timeoutTimeMillis) {
-            synchronized (waitLockForA11yOff) {
-                if (!manager.isEnabled()) {
-                    return;
-                }
-                try {
-                    waitLockForA11yOff.wait(timeoutTimeMillis - SystemClock.uptimeMillis());
-                } catch (InterruptedException e) {
-                    // Ignored; loop again
-                }
-            }
-        }
-        throw new RuntimeException("Unable to turn accessibility off");
-    }
-
-    private void enableTestService() throws Exception {
-        Context context = getInstrumentation().getContext();
-        AccessibilityManager manager =
-                (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
-        List<AccessibilityServiceInfo> serviceInfos =
-                manager.getInstalledAccessibilityServiceList();
-        for (int i = 0; i < serviceInfos.size(); i++) {
-            AccessibilityServiceInfo serviceInfo = serviceInfos.get(i);
-            if (context.getString(R.string.soft_keyboard_modes_accessibility_service_description)
-                    .equals(serviceInfo.getDescription())) {
-                ContentResolver cr = context.getContentResolver();
-                UiAutomation uiAutomation = getUiAutomation();
-                String command = "settings put secure "
-                        + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES + " "
-                        + serviceInfo.getId();
-                executeShellCommand(uiAutomation, command);
-                executeShellCommand(uiAutomation, "settings put secure "
-                        + Settings.Secure.ACCESSIBILITY_ENABLED + " 1");
-                uiAutomation.destroy();
-
-                // We have enabled the services of interest and need to wait until they
-                // are instantiated and started (if needed) and the system binds to them.
-                long timeoutTimeMillis = SystemClock.uptimeMillis() + TIMEOUT_SERVICE_TOGGLE_MS;
-                while (SystemClock.uptimeMillis() < timeoutTimeMillis) {
-                    synchronized(
-                            StubSoftKeyboardModesAccessibilityService.sWaitObjectForConnecting) {
-                        if (StubSoftKeyboardModesAccessibilityService.sInstance != null) {
-                            mService = StubSoftKeyboardModesAccessibilityService.sInstance;
-                            mKeyboardController = mService.getTestSoftKeyboardController();
-                            return;
-                        }
-                        try {
-                            StubSoftKeyboardModesAccessibilityService.sWaitObjectForConnecting.wait(
-                                    timeoutTimeMillis - SystemClock.uptimeMillis());
-                        } catch (InterruptedException e) {
-                            // Ignored; loop again
-                        }
-                    }
-                }
-                throw new IllegalStateException("Stub accessibility service not started");
-            }
-        }
-        throw new IllegalStateException("Stub accessiblity service not found");
-    }
-
     private void waitForIdle() throws TimeoutException {
-        getUiAutomation().waitForIdle(TIMEOUT_ACCESSIBILITY_STATE_IDLE, TIMEOUT_ASYNC_PROCESSING);
+        mUiAutomation.waitForIdle(TIMEOUT_ACCESSIBILITY_STATE_IDLE, TIMEOUT_ASYNC_PROCESSING);
     }
 
     /**
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java
new file mode 100644
index 0000000..e94cb11
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java
@@ -0,0 +1,139 @@
+/**
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accessibilityservice.cts;
+
+import android.app.UiAutomation;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import android.accessibilityservice.cts.R;
+
+/**
+ * Test cases for actions taken on text views.
+ */
+public class AccessibilityTextActionTest extends
+        AccessibilityActivityTestCase<AccessibilityTextTraversalActivity> {
+    UiAutomation mUiAutomation;
+
+    public AccessibilityTextActionTest() {
+        super(AccessibilityTextTraversalActivity.class);
+    }
+
+    public void setUp() throws Exception {
+        super.setUp();
+        mUiAutomation = getInstrumentation().getUiAutomation();
+    }
+
+    public void tearDown() throws Exception {
+        mUiAutomation.destroy();
+        super.tearDown();
+    }
+
+    public void testNotEditableTextView_shouldNotExposeOrRespondToSetTextAction() {
+        final TextView textView = (TextView) getActivity().findViewById(R.id.text);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                textView.setVisibility(View.VISIBLE);
+                textView.setText(getString(R.string.a_b));
+            }
+        });
+
+        final AccessibilityNodeInfo text = mUiAutomation.getRootInActiveWindow()
+                .findAccessibilityNodeInfosByText(getString(R.string.a_b)).get(0);
+
+        assertFalse("Standard text view should not support SET_TEXT", text.getActionList()
+                .contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_TEXT));
+        assertEquals("Standard text view should not support SET_TEXT", 0,
+                text.getActions() & AccessibilityNodeInfo.ACTION_SET_TEXT);
+        Bundle args = new Bundle();
+        args.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
+                getString(R.string.text_input_blah));
+        assertFalse(text.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args));
+
+        getInstrumentation().waitForIdleSync();
+        assertTrue("Text view should not update on failed set text",
+                TextUtils.equals(getString(R.string.a_b), textView.getText()));
+    }
+
+    public void testEditableTextView_shouldExposeAndRespondToSetTextAction() {
+        final TextView textView = (TextView) getActivity().findViewById(R.id.text);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                textView.setVisibility(View.VISIBLE);
+                textView.setText(getString(R.string.a_b), TextView.BufferType.EDITABLE);
+            }
+        });
+
+        final AccessibilityNodeInfo text = mUiAutomation.getRootInActiveWindow()
+                .findAccessibilityNodeInfosByText(getString(R.string.a_b)).get(0);
+
+        assertTrue("Editable text view should support SET_TEXT", text.getActionList()
+                .contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_TEXT));
+        assertEquals("Editable text view should support SET_TEXT",
+                AccessibilityNodeInfo.ACTION_SET_TEXT,
+                text.getActions() & AccessibilityNodeInfo.ACTION_SET_TEXT);
+
+        Bundle args = new Bundle();
+        String textToSet = getString(R.string.text_input_blah);
+        args.putCharSequence(
+                AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, textToSet);
+
+        assertTrue(text.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args));
+
+        getInstrumentation().waitForIdleSync();
+        assertTrue("Editable text should update on set text",
+                TextUtils.equals(textToSet, textView.getText()));
+    }
+
+    public void testEditText_shouldExposeAndRespondToSetTextAction() {
+        final EditText editText = (EditText) getActivity().findViewById(R.id.edit);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                editText.setVisibility(View.VISIBLE);
+                editText.setText(getString(R.string.a_b));
+            }
+        });
+
+        final AccessibilityNodeInfo text = mUiAutomation.getRootInActiveWindow()
+                .findAccessibilityNodeInfosByText(getString(R.string.a_b)).get(0);
+
+        assertTrue("EditText should support SET_TEXT", text.getActionList()
+                .contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_TEXT));
+        assertEquals("EditText view should support SET_TEXT",
+                AccessibilityNodeInfo.ACTION_SET_TEXT,
+                text.getActions() & AccessibilityNodeInfo.ACTION_SET_TEXT);
+
+        Bundle args = new Bundle();
+        String textToSet = getString(R.string.text_input_blah);
+        args.putCharSequence(
+                AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, textToSet);
+
+        assertTrue(text.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args));
+
+        getInstrumentation().waitForIdleSync();
+        assertTrue("EditText should update on set text",
+                TextUtils.equals(textToSet, editText.getText()));
+    }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java
index 69acfcd..53eec5f 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextTraversalTest.java
@@ -42,10 +42,6 @@
         super(AccessibilityTextTraversalActivity.class);
     }
 
-    public void tearDown() {
-        getInstrumentation().getUiAutomation().destroy();
-    }
-
     @MediumTest
     public void testActionNextAndPreviousAtGranularityCharacterOverContentDescription()
             throws Exception {
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java
index b04e98b..a292e4e 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityViewTreeReportingTest.java
@@ -39,10 +39,6 @@
         super(AccessibilityViewTreeReportingActivity.class);
     }
 
-    public void tearDown() {
-        getInstrumentation().getUiAutomation().destroy();
-    }
-
     @MediumTest
     public void testDescendantsOfNotImportantViewReportedInOrder1() throws Exception {
         UiAutomation uiAutomation = getUiAutomation(false);
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
index 12c251b..d328916 100755
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
@@ -60,10 +60,6 @@
         super(AccessibilityWindowQueryActivity.class);
     }
 
-    public void tearDown() {
-        getInstrumentation().getUiAutomation().destroy();
-    }
-
     @MediumTest
     public void testFindByText() throws Exception {
         // find a view by text
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingActivity.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingActivity.java
new file mode 100644
index 0000000..d17a285
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingActivity.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accessibilityservice.cts;
+
+import android.os.Bundle;
+
+/**
+ * Activity used by ActivityWindowReportingTest
+ */
+public class AccessibilityWindowReportingActivity extends AccessibilityTestActivity {
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.accessibility_window_reporting_test);
+    }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
new file mode 100644
index 0000000..dec3131
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accessibilityservice.cts;
+
+import android.accessibilityservice.AccessibilityService;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.app.UiAutomation;
+import android.text.TextUtils;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityWindowInfo;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Tests that AccessibilityWindowInfos are properly populated
+ */
+public class AccessibilityWindowReportingTest
+        extends AccessibilityActivityTestCase<AccessibilityWindowReportingActivity> {
+    UiAutomation mUiAutomation;
+
+    public AccessibilityWindowReportingTest() {
+        super(AccessibilityWindowReportingActivity.class);
+    }
+
+    public void setUp() throws Exception {
+        super.setUp();
+        mUiAutomation = getInstrumentation().getUiAutomation();
+        AccessibilityServiceInfo info = mUiAutomation.getServiceInfo();
+        info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
+        mUiAutomation.setServiceInfo(info);
+    }
+
+    public void tearDown() throws Exception {
+        mUiAutomation.destroy();
+        super.tearDown();
+    }
+
+    public void testWindowTitle_getTitleReturnsTitle() {
+        final String title = "Some title";
+        setTitleSync(title);
+        AccessibilityWindowInfo window = findWindowByTitle(title);
+        assertNotNull("Window title not reported to accessibility", window);
+        window.recycle();
+    }
+
+    public void testGetAnchorForDropDownForAutoCompleteTextView_returnsTextViewNode() {
+        final AutoCompleteTextView autoCompleteTextView =
+                (AutoCompleteTextView) getActivity().findViewById(R.id.autoCompleteLayout);
+        AccessibilityNodeInfo autoCompleteTextInfo = mUiAutomation.getRootInActiveWindow()
+                .findAccessibilityNodeInfosByViewId(
+                        "android.accessibilityservice.cts:id/autoCompleteLayout")
+                .get(0);
+
+        // For the drop-down
+        final String[] COUNTRIES = new String[] {"Belgium", "France", "Italy", "Germany", "Spain"};
+
+        try {
+            mUiAutomation.executeAndWaitForEvent(new Runnable() {
+                @Override
+                public void run() {
+                    getInstrumentation().runOnMainSync(new Runnable() {
+                        @Override
+                        public void run() {
+                            ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
+                                    android.R.layout.simple_dropdown_item_1line, COUNTRIES);
+                            autoCompleteTextView.setAdapter(adapter);
+                            autoCompleteTextView.showDropDown();
+                        }
+                    });
+                }
+            }, new UiAutomation.AccessibilityEventFilter() {
+                @Override
+                public boolean accept(AccessibilityEvent event) {
+                    return event.getEventType() == AccessibilityEvent.TYPE_WINDOWS_CHANGED;
+                }
+            }, TIMEOUT_ASYNC_PROCESSING);
+        } catch (TimeoutException exception) {
+            throw new RuntimeException(
+                    "Failed to get window changed event when showing dropdown", exception);
+        }
+
+        // Find the pop-up window
+        boolean foundPopup = false;
+        List<AccessibilityWindowInfo> windows = mUiAutomation.getWindows();
+        for (int i = 0; i < windows.size(); i++) {
+            AccessibilityWindowInfo window = windows.get(i);
+            if (window.getAnchor() == null) {
+                continue;
+            }
+            assertEquals(autoCompleteTextInfo, window.getAnchor());
+            assertFalse("Found multiple pop-ups anchored to one text view", foundPopup);
+            foundPopup = true;
+        }
+        assertTrue("Failed to find accessibility window for auto-complete pop-up", foundPopup);
+    }
+
+    private AccessibilityWindowInfo findWindowByTitle(CharSequence title) {
+        List<AccessibilityWindowInfo> windows = mUiAutomation.getWindows();
+        AccessibilityWindowInfo returnValue = null;
+        for (int i = 0; i < windows.size(); i++) {
+            AccessibilityWindowInfo window = windows.get(i);
+            if (TextUtils.equals(title, window.getTitle())) {
+                returnValue = window;
+            } else {
+                window.recycle();
+            }
+        }
+        return returnValue;
+    }
+
+    private void setTitleSync(final String title) {
+        try {
+            waitForIdle();
+            mUiAutomation.executeAndWaitForEvent(new Runnable() {
+                @Override
+                public void run() {
+                    getInstrumentation().runOnMainSync(new Runnable() {
+                        @Override
+                        public void run() {
+                            getActivity().getWindow().setTitle(title);
+                        }
+                    });
+                    // TODO: Setting the title should trigger an update of windows
+                    mUiAutomation.performGlobalAction(
+                            AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN);
+                    mUiAutomation.performGlobalAction(
+                            AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN);
+                }
+            }, new UiAutomation.AccessibilityEventFilter() {
+                @Override
+                public boolean accept(AccessibilityEvent event) {
+                    return event.getEventType() == AccessibilityEvent.TYPE_WINDOWS_CHANGED;
+                }
+            }, TIMEOUT_ASYNC_PROCESSING);
+        } catch (TimeoutException exception) {
+            throw new RuntimeException(
+                    "Failed to get window changed event on title change", exception);
+        }
+    }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/InstrumentedAccessibilityService.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/InstrumentedAccessibilityService.java
index 2aeb5b8..99efb2c 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/InstrumentedAccessibilityService.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/InstrumentedAccessibilityService.java
@@ -93,7 +93,9 @@
         final String enabledServices = Settings.Secure.getString(
                 context.getContentResolver(),
                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
-        assertFalse("Service is already enabled", enabledServices.contains(serviceName));
+        if (enabledServices != null) {
+            assertFalse("Service is already enabled", enabledServices.contains(serviceName));
+        }
 
         final AccessibilityManager manager = (AccessibilityManager) context.getSystemService(
                 Context.ACCESSIBILITY_SERVICE);
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/ShellCommandBuilder.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/ShellCommandBuilder.java
index 7509f18..1ad55fc 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/ShellCommandBuilder.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/ShellCommandBuilder.java
@@ -42,7 +42,8 @@
     }
 
     public void run() {
-        final UiAutomation automation = getUiAutomationSafe(mTestCase);
+        final UiAutomation automation = mTestCase.getInstrumentation().getUiAutomation(
+                UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
         for (String command : mCommands) {
             execShellCommand(automation, command);
         }
@@ -68,27 +69,6 @@
         return this;
     }
 
-    private static UiAutomation getUiAutomationSafe(InstrumentationTestCase testCase) {
-        UiAutomation uiAutomation;
-        try {
-            uiAutomation = getUiAutomation(testCase);
-        } catch (RuntimeException e) {
-            // Clean up UI Automation after other tests as we cannot request UI Automation with
-            // different flags if one already exists.
-            uiAutomation = testCase.getInstrumentation().getUiAutomation();
-            uiAutomation.destroy();
-
-            // Try to get UI Automation again.
-            uiAutomation = getUiAutomation(testCase);
-        }
-        return uiAutomation;
-    }
-
-    private static UiAutomation getUiAutomation(InstrumentationTestCase testCase) {
-        return testCase.getInstrumentation().getUiAutomation(
-                UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
-    }
-
     private static void execShellCommand(UiAutomation automation, String command) {
         try (ParcelFileDescriptor fd = automation.executeShellCommand(command)) {
             try (InputStream inputStream = new FileInputStream(fd.getFileDescriptor())) {
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/StubSoftKeyboardModesAccessibilityService.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/StubSoftKeyboardModesAccessibilityService.java
deleted file mode 100644
index 27d51d9..0000000
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/StubSoftKeyboardModesAccessibilityService.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.accessibilityservice.cts;
-
-import android.accessibilityservice.AccessibilityService;
-import android.content.Intent;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityWindowInfo;
-
-/**
- * Stub accessibility service for testing APIs to show/hide Soft Keyboard.
- */
-public class StubSoftKeyboardModesAccessibilityService extends AccessibilityService {
-
-    public static Object sWaitObjectForConnecting = new Object();
-
-    public static StubSoftKeyboardModesAccessibilityService sInstance = null;
-
-    @Override
-    protected void onServiceConnected() {
-        synchronized (sWaitObjectForConnecting) {
-            sInstance = this;
-            sWaitObjectForConnecting.notifyAll();
-        }
-    }
-
-    @Override
-    public void onDestroy() {
-        sInstance = null;
-        super.onDestroy();
-    }
-
-    @Override
-    public void onAccessibilityEvent(AccessibilityEvent event) {
-        /* do nothing */
-    }
-
-    @Override
-    public void onInterrupt() {
-        /* do nothing */
-    }
-
-    public SoftKeyboardController getTestSoftKeyboardController() {
-        return sInstance.getSoftKeyboardController();
-    }
-
-    public int getTestWindowsListSize() {
-        return sInstance.getWindows().size();
-    }
-}
diff --git a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
index 9ecdc2d..5c97d5c 100644
--- a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
@@ -301,7 +301,7 @@
                     // simulate real scenario (preview runs a bit)
                     waitForNumResults(previewResultListener, NUM_RESULTS_WAIT);
 
-                    stopPreview();
+                    stopPreviewAndDrain();
 
                 }
                 mReportLog.addValues("Camera " + id
diff --git a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
index 539304c..76c91aa 100644
--- a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
+++ b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
@@ -216,12 +216,25 @@
     }
 
     /**
-     * Stop preview for current camera device.
+     * Stop preview for current camera device by closing the session.
+     * Does _not_ wait for the device to go idle
      */
     protected void stopPreview() throws Exception {
+        if (VERBOSE) Log.v(TAG, "Stopping preview");
+        // Stop repeat, wait for captures to complete, and disconnect from surfaces
+        mSession.close();
+    }
+
+    /**
+     * Stop preview for current camera device by closing the session and waiting for it to close,
+     * resulting in an idle device.
+     */
+    protected void stopPreviewAndDrain() throws Exception {
         if (VERBOSE) Log.v(TAG, "Stopping preview and waiting for idle");
         // Stop repeat, wait for captures to complete, and disconnect from surfaces
         mSession.close();
+        mSessionListener.getStateWaiter().waitForState(BlockingSessionCallback.SESSION_CLOSED,
+                /*timeoutMs*/WAIT_FOR_RESULT_TIMEOUT_MS);
     }
 
     /**
diff --git a/tests/core/libcore/tests/Android.mk b/tests/core/libcore/tests/Android.mk
index 82ab12e..6429558 100644
--- a/tests/core/libcore/tests/Android.mk
+++ b/tests/core/libcore/tests/Android.mk
@@ -16,6 +16,6 @@
 
 include $(CLEAR_VARS)
 LOCAL_PACKAGE_NAME := android.core.tests.libcore.package.tests
-LOCAL_STATIC_JAVA_LIBRARIES := core-tests
+LOCAL_STATIC_JAVA_LIBRARIES := core-tests mockito-target-minus-junit4
 LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 include $(BUILD_CTSCORE_PACKAGE)
diff --git a/tests/core/runner/Android.mk b/tests/core/runner/Android.mk
index 158a1f1..1355512 100644
--- a/tests/core/runner/Android.mk
+++ b/tests/core/runner/Android.mk
@@ -23,12 +23,44 @@
 # include this package in the tests target for continuous testing
 LOCAL_MODULE_TAGS := tests
 
-LOCAL_SRC_FILES := $(call all-java-files-under,src)
-
 LOCAL_PACKAGE_NAME := android.core.tests.runner
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := cts-test-runner
 
 LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 
 include $(BUILD_CTSCORE_PACKAGE)
+
+#==========================================================
+# Build the core runner.
+#==========================================================
+
+# Build library
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_MODULE := cts-core-test-runner
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    compatibility-device-util \
+    android-support-test \
+    android.test.runner \
+    vogarexpect
+
+LOCAL_JAVA_LANGUAGE_VERSION := 1.8
+
+include $(BUILD_JAVA_LIBRARY)
+
+#==========================================================
+# Build the run listener
+#==========================================================
+
+# Build library
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := $(call all-java-files-under,src/com/android/cts/runner)
+LOCAL_MODULE := cts-test-runner
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+include $(BUILD_JAVA_LIBRARY)
diff --git a/tests/tests/icu/src/android/icu/cts/AndroidJUnitRunnerConstants.java b/tests/core/runner/src/com/android/cts/core/runner/AndroidJUnitRunnerConstants.java
similarity index 95%
rename from tests/tests/icu/src/android/icu/cts/AndroidJUnitRunnerConstants.java
rename to tests/core/runner/src/com/android/cts/core/runner/AndroidJUnitRunnerConstants.java
index 24d8819..c6c8504 100644
--- a/tests/tests/icu/src/android/icu/cts/AndroidJUnitRunnerConstants.java
+++ b/tests/core/runner/src/com/android/cts/core/runner/AndroidJUnitRunnerConstants.java
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package android.icu.cts;
+package com.android.cts.core.runner;
 
 import android.support.test.runner.AndroidJUnitRunner;
 
 /**
  * Constants used to communicate to and from {@link AndroidJUnitRunner}.
  */
-interface AndroidJUnitRunnerConstants {
+public interface AndroidJUnitRunnerConstants {
 
     /**
      * The names of the file containing the names of the tests to run.
@@ -82,5 +82,5 @@
     /**
      * An identifier for tests run using this class.
      */
-    String REPORT_VALUE_ID = "IcuTestRunner";
+    String REPORT_VALUE_ID = "CoreTestRunner";
 }
diff --git a/tests/tests/icu/src/android/icu/cts/IcuTestRunner.java b/tests/core/runner/src/com/android/cts/core/runner/CoreTestRunner.java
similarity index 72%
rename from tests/tests/icu/src/android/icu/cts/IcuTestRunner.java
rename to tests/core/runner/src/com/android/cts/core/runner/CoreTestRunner.java
index 51c4999..144e9e2 100644
--- a/tests/tests/icu/src/android/icu/cts/IcuTestRunner.java
+++ b/tests/core/runner/src/com/android/cts/core/runner/CoreTestRunner.java
@@ -14,21 +14,21 @@
  * limitations under the License.
  */
 
-package android.icu.cts;
+package com.android.cts.core.runner;
 
 import android.app.Activity;
 import android.app.Instrumentation;
-import android.icu.junit.IcuTestRunnerBuilder;
+import com.android.cts.core.runner.support.ExtendedAndroidRunnerBuilder;
 import android.os.Bundle;
 import android.os.Debug;
 import android.support.test.internal.util.AndroidRunnerParams;
 import android.util.Log;
+import com.google.common.base.Splitter;
 import java.io.BufferedReader;
 import java.io.FileReader;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
@@ -45,22 +45,26 @@
 import vogar.ExpectationStore;
 import vogar.ModeId;
 
-import static android.icu.cts.AndroidJUnitRunnerConstants.ARGUMENT_COUNT;
-import static android.icu.cts.AndroidJUnitRunnerConstants.ARGUMENT_DEBUG;
-import static android.icu.cts.AndroidJUnitRunnerConstants.ARGUMENT_LOG_ONLY;
-import static android.icu.cts.AndroidJUnitRunnerConstants.ARGUMENT_TEST_CLASS;
-import static android.icu.cts.AndroidJUnitRunnerConstants.ARGUMENT_TEST_FILE;
+import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_COUNT;
+import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_DEBUG;
+import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_LOG_ONLY;
+import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_TEST_CLASS;
+import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.ARGUMENT_TEST_FILE;
 
 /**
  * A drop-in replacement for AndroidJUnitTestRunner, which understands the same arguments, and has
- * similar functionality, but runs ICU tests instead of calling the JUnit wrapper.
+ * similar functionality, but can filter by expectations and allows a custom runner-builder to be
+ * provided.
  */
-public final class IcuTestRunner extends Instrumentation {
+public class CoreTestRunner extends Instrumentation {
 
-    public static final String TAG = "IcuTestRunner";
+    public static final String TAG = "LibcoreTestRunner";
 
-    private static final List<String> EXPECTATIONS_PATHS =
-            Collections.singletonList("expectations/icu-known-failures.txt");
+    private static final java.lang.String ARGUMENT_ROOT_CLASSES = "core-root-classes";
+
+    private static final String ARGUMENT_EXPECTATIONS = "core-expectations";
+
+    private static final Splitter CLASS_LIST_SPLITTER = Splitter.on(',').trimResults();
 
     /** The args for the runner. */
     private Bundle args;
@@ -80,10 +84,10 @@
     /**
      * The list of tests to run.
      */
-    private IcuTestList icuTestList;
+    private TestList testList;
 
     @Override
-    public void onCreate(Bundle args) {
+    public void onCreate(final Bundle args) {
         super.onCreate(args);
         this.args = args;
 
@@ -102,7 +106,9 @@
         this.testCountOnly = args.getBoolean(ARGUMENT_COUNT);
 
         try {
-            Set<String> expectationResources = new LinkedHashSet<>(EXPECTATIONS_PATHS);
+            // Get the set of resource names containing the expectations.
+            Set<String> expectationResources = new LinkedHashSet<>(
+                    CLASS_LIST_SPLITTER.splitToList(args.getString(ARGUMENT_EXPECTATIONS)));
             expectationStore = ExpectationStore.parseResources(
                     getClass(), expectationResources, ModeId.DEVICE);
         } catch (IOException e) {
@@ -131,11 +137,16 @@
         }
 
         if (testNameList == null) {
-            icuTestList = IcuTestList.rootList(Arrays.asList(
-                    "android.icu.cts.coverage.TestAll",
-                    "android.icu.dev.test.TestAll"));
+            String rootClasses = args.getString(ARGUMENT_ROOT_CLASSES);
+            if (rootClasses == null) {
+                throw new IllegalStateException(
+                        "No tests specified, neither exclusive list or root class");
+            } else {
+                List<String> roots = CLASS_LIST_SPLITTER.splitToList(rootClasses);
+                testList = TestList.rootList(roots);
+            }
         } else {
-            icuTestList = IcuTestList.exclusiveList(testNameList);
+            testList = TestList.exclusiveList(testNameList);
         }
 
         start();
@@ -157,15 +168,15 @@
         Request request;
         int totalTestCount;
         try {
-            RunnerBuilder runnerBuilder = new IcuTestRunnerBuilder(runnerParams);
-            Class[] classes = icuTestList.getClassesToRun();
+            RunnerBuilder runnerBuilder = new ExtendedAndroidRunnerBuilder(runnerParams);
+            Class[] classes = testList.getClassesToRun();
             Runner suite = new Computer().getSuite(runnerBuilder, classes);
 
             if (suite instanceof Filterable) {
                 Filterable filterable = (Filterable) suite;
 
                 // Filter out all the tests that are expected to fail.
-                Filter filter = new IcuTestFilter(icuTestList, expectationStore);
+                Filter filter = new TestFilter(testList, expectationStore);
 
                 try {
                     filterable.filter(filter);
@@ -183,17 +194,18 @@
             throw new RuntimeException("Could not create a suite", e);
         }
 
-        IcuRunListener icuRunListener = new IcuRunListener(this, runnerParams, totalTestCount);
-        core.addListener(icuRunListener);
+        StatusUpdaterRunListener statusUpdaterRunListener =
+                new StatusUpdaterRunListener(this, runnerParams, totalTestCount);
+        core.addListener(statusUpdaterRunListener);
         core.run(request);
 
         Bundle results;
         if (testCountOnly) {
-            results = icuRunListener.getCountResults();
+            results = statusUpdaterRunListener.getCountResults();
             Log.d(TAG, "test count only: " + results);
         } else {
             // Get the final results to send back.
-            results = icuRunListener.getFinalResults();
+            results = statusUpdaterRunListener.getFinalResults();
         }
 
         Log.d(TAG, "Finished");
diff --git a/tests/tests/icu/src/android/icu/cts/IcuRunListener.java b/tests/core/runner/src/com/android/cts/core/runner/StatusUpdaterRunListener.java
similarity index 92%
rename from tests/tests/icu/src/android/icu/cts/IcuRunListener.java
rename to tests/core/runner/src/com/android/cts/core/runner/StatusUpdaterRunListener.java
index 0a6f355..429ae92 100644
--- a/tests/tests/icu/src/android/icu/cts/IcuRunListener.java
+++ b/tests/core/runner/src/com/android/cts/core/runner/StatusUpdaterRunListener.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.icu.cts;
+package com.android.cts.core.runner;
 
 import android.app.Instrumentation;
 import android.os.Bundle;
@@ -30,8 +30,8 @@
 
 import static android.app.Instrumentation.REPORT_KEY_IDENTIFIER;
 import static android.app.Instrumentation.REPORT_KEY_STREAMRESULT;
-import static android.icu.cts.AndroidJUnitRunnerConstants.REPORT_KEY_RUNTIME;
-import static android.icu.cts.AndroidJUnitRunnerConstants.REPORT_VALUE_ID;
+import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.REPORT_KEY_RUNTIME;
+import static com.android.cts.core.runner.AndroidJUnitRunnerConstants.REPORT_VALUE_ID;
 import static android.test.InstrumentationTestRunner.REPORT_KEY_NAME_CLASS;
 import static android.test.InstrumentationTestRunner.REPORT_KEY_NAME_TEST;
 import static android.test.InstrumentationTestRunner.REPORT_KEY_NUM_CURRENT;
@@ -47,7 +47,7 @@
  * Listens to result of running tests, collates details and sends intermediate status information
  * back to the host.
  */
-class IcuRunListener extends RunListener {
+class StatusUpdaterRunListener extends RunListener {
 
     /**
      * The {@link Instrumentation} for which this will report information.
@@ -77,7 +77,8 @@
 
     private long testStartTime;
 
-    public IcuRunListener(Instrumentation instrumentation, AndroidRunnerParams runnerParams,
+    public StatusUpdaterRunListener(Instrumentation instrumentation,
+            AndroidRunnerParams runnerParams,
             int totalTestCount) {
         this.instrumentation = instrumentation;
         this.runnerParams = runnerParams;
@@ -135,6 +136,7 @@
         } else {
             resultStatus = REPORT_VALUE_RESULT_ERROR;
         }
+
         String information = failure.getTrace();
         currentTestResult.putString(REPORT_KEY_STACK, information);
         String output = "Error: " + description + "\n" + information;
@@ -165,7 +167,7 @@
 
     public Bundle getFinalResults() {
         int totalTests = totalFailures + totalSuccess;
-        Log.d(IcuTestRunner.TAG, (runnerParams.isSkipExecution() ? "Skipped " : "Ran ")
+        Log.d(CoreTestRunner.TAG, (runnerParams.isSkipExecution() ? "Skipped " : "Ran ")
                 + totalTests + " tests, " + totalSuccess + " passed, " + totalFailures + " failed");
         Bundle results = new Bundle();
         results.putString(REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID);
@@ -189,7 +191,7 @@
     }
 
     public Bundle getCountResults() {
-        Log.d(IcuTestRunner.TAG, "Counted " + (totalFailures + totalSuccess) + " tests, "
+        Log.d(CoreTestRunner.TAG, "Counted " + (totalFailures + totalSuccess) + " tests, "
                 + totalSuccess + " passed, " + totalFailures + " failed");
         Bundle results = new Bundle();
         results.putString(REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID);
diff --git a/tests/tests/icu/src/android/icu/cts/IcuTestFilter.java b/tests/core/runner/src/com/android/cts/core/runner/TestFilter.java
similarity index 90%
rename from tests/tests/icu/src/android/icu/cts/IcuTestFilter.java
rename to tests/core/runner/src/com/android/cts/core/runner/TestFilter.java
index 3da2976..8cadbcf 100644
--- a/tests/tests/icu/src/android/icu/cts/IcuTestFilter.java
+++ b/tests/core/runner/src/com/android/cts/core/runner/TestFilter.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.icu.cts;
+package com.android.cts.core.runner;
 
 import android.util.Log;
 import java.util.List;
@@ -61,15 +61,15 @@
  * {@link ParentRunner}, as that would prevent it from traversing the hierarchy and finding
  * the leaf nodes.
  */
-class IcuTestFilter extends Filter {
+class TestFilter extends Filter {
 
     private final ExpectationStore expectationStore;
 
-    private final IcuTestList icuTestList;
+    private final TestList testList;
 
-    public IcuTestFilter(IcuTestList icuTestList, @Nullable ExpectationStore expectationStore) {
+    public TestFilter(TestList testList, @Nullable ExpectationStore expectationStore) {
         this.expectationStore = expectationStore;
-        this.icuTestList = icuTestList;
+        this.testList = testList;
     }
 
     @Override
@@ -84,14 +84,14 @@
             String testName = className + "#" + methodName;
 
             // If the test isn't in the list of tests to run then do not run it.
-            if (!icuTestList.shouldRunTest(testName)) {
+            if (!testList.shouldRunTest(testName)) {
                 return false;
             }
 
             if (expectationStore != null) {
                 Expectation expectation = expectationStore.get(testName);
                 if (expectation.getResult() != Result.SUCCESS) {
-                    Log.d(IcuTestRunner.TAG, "Excluding test " + description
+                    Log.d(CoreTestRunner.TAG, "Excluding test " + testDescription
                             + " as it matches expectation: " + expectation);
                     return false;
                 }
@@ -126,6 +126,6 @@
 
     @Override
     public String describe() {
-        return "IcuTestFilter";
+        return "TestFilter";
     }
 }
diff --git a/tests/tests/icu/src/android/icu/cts/IcuTestList.java b/tests/core/runner/src/com/android/cts/core/runner/TestList.java
similarity index 84%
rename from tests/tests/icu/src/android/icu/cts/IcuTestList.java
rename to tests/core/runner/src/com/android/cts/core/runner/TestList.java
index a9c3c5f..4b0452d 100644
--- a/tests/tests/icu/src/android/icu/cts/IcuTestList.java
+++ b/tests/core/runner/src/com/android/cts/core/runner/TestList.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.icu.cts;
+package com.android.cts.core.runner;
 
 import android.util.Log;
 import java.util.ArrayList;
@@ -25,7 +25,7 @@
 /**
  * A list of the tests to run.
  */
-class IcuTestList {
+class TestList {
 
     /**
      * The names of the set of tests to run, if null then all tests should be run.
@@ -35,7 +35,7 @@
 
     private final List<Class<?>> classesToRun;
 
-    public static IcuTestList exclusiveList(List<String> testNameList) {
+    public static TestList exclusiveList(List<String> testNameList) {
         Set<String> classNamesToRun = new LinkedHashSet<>();
         Set<String> testsToRun = new LinkedHashSet<>(testNameList);
 
@@ -50,19 +50,19 @@
             classNamesToRun.add(className);
         }
 
-        Log.d(IcuTestRunner.TAG, "Running only the following tests: " + testsToRun);
-        return new IcuTestList(getClasses(classNamesToRun), testsToRun);
+        Log.d(CoreTestRunner.TAG, "Running only the following tests: " + testsToRun);
+        return new TestList(getClasses(classNamesToRun), testsToRun);
     }
 
-    public static IcuTestList rootList(List<String> rootList) {
+    public static TestList rootList(List<String> rootList) {
 
         // Run from the root test class.
         Set<String> classNamesToRun = new LinkedHashSet<>(rootList);
-        Log.d(IcuTestRunner.TAG, "Running all tests rooted at " + classNamesToRun);
+        Log.d(CoreTestRunner.TAG, "Running all tests rooted at " + classNamesToRun);
 
         List<Class<?>> classesToRun1 = getClasses(classNamesToRun);
 
-        return new IcuTestList(classesToRun1, null);
+        return new TestList(classesToRun1, null);
     }
 
     private static List<Class<?>> getClasses(Set<String> classNames) {
@@ -83,7 +83,7 @@
      * @param testsToRun The exclusive set of tests to run or null if all tests reachable from the
      * classes are to be run.
      */
-    private IcuTestList(List<Class<?>> classes, Set<String> testsToRun) {
+    private TestList(List<Class<?>> classes, Set<String> testsToRun) {
         this.testsToRun = testsToRun;
         this.classesToRun = classes;
     }
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/AndroidRunnerBuilder.java b/tests/core/runner/src/com/android/cts/core/runner/support/AndroidRunnerBuilder.java
new file mode 100644
index 0000000..bdb3e57
--- /dev/null
+++ b/tests/core/runner/src/com/android/cts/core/runner/support/AndroidRunnerBuilder.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.core.runner.support;
+
+import android.support.test.internal.runner.junit3.AndroidJUnit3Builder;
+import android.support.test.internal.runner.junit3.AndroidSuiteBuilder;
+import android.support.test.internal.runner.junit4.AndroidAnnotatedBuilder;
+import android.support.test.internal.runner.junit4.AndroidJUnit4Builder;
+import android.support.test.internal.util.AndroidRunnerParams;
+
+import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
+import org.junit.internal.builders.AnnotatedBuilder;
+import org.junit.internal.builders.IgnoredBuilder;
+import org.junit.internal.builders.JUnit3Builder;
+import org.junit.internal.builders.JUnit4Builder;
+import org.junit.runners.model.RunnerBuilder;
+
+/**
+ * A {@link RunnerBuilder} that can handle all types of tests.
+ */
+// A copy of package private class android.support.test.internal.runner.AndroidRunnerBuilder.
+// Copied here so that it can be extended.
+class AndroidRunnerBuilder extends AllDefaultPossibilitiesBuilder {
+
+    private final AndroidJUnit3Builder mAndroidJUnit3Builder;
+    private final AndroidJUnit4Builder mAndroidJUnit4Builder;
+    private final AndroidSuiteBuilder mAndroidSuiteBuilder;
+    private final AndroidAnnotatedBuilder mAndroidAnnotatedBuilder;
+    // TODO: customize for Android ?
+    private final IgnoredBuilder mIgnoredBuilder;
+
+    /**
+     * @param runnerParams {@link AndroidRunnerParams} that stores common runner parameters
+     */
+    AndroidRunnerBuilder(AndroidRunnerParams runnerParams) {
+        super(true);
+        mAndroidJUnit3Builder = new AndroidJUnit3Builder(runnerParams);
+        mAndroidJUnit4Builder = new AndroidJUnit4Builder(runnerParams);
+        mAndroidSuiteBuilder = new AndroidSuiteBuilder(runnerParams);
+        mAndroidAnnotatedBuilder = new AndroidAnnotatedBuilder(this, runnerParams);
+        mIgnoredBuilder = new IgnoredBuilder();
+    }
+
+    @Override
+    protected JUnit4Builder junit4Builder() {
+        return mAndroidJUnit4Builder;
+    }
+
+    @Override
+    protected JUnit3Builder junit3Builder() {
+        return mAndroidJUnit3Builder;
+    }
+
+    @Override
+    protected AnnotatedBuilder annotatedBuilder() {
+        return mAndroidAnnotatedBuilder;
+    }
+
+    @Override
+    protected IgnoredBuilder ignoredBuilder() {
+        return mIgnoredBuilder;
+    }
+
+    @Override
+    protected RunnerBuilder suiteMethodBuilder() {
+        return mAndroidSuiteBuilder;
+    }
+}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidAnnotatedBuilder.java b/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidAnnotatedBuilder.java
new file mode 100644
index 0000000..05c6623
--- /dev/null
+++ b/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidAnnotatedBuilder.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.core.runner.support;
+
+import android.support.test.internal.runner.junit4.AndroidAnnotatedBuilder;
+import android.support.test.internal.util.AndroidRunnerParams;
+import android.support.test.runner.AndroidJUnit4;
+import junit.framework.TestCase;
+import org.junit.runner.RunWith;
+import org.junit.runner.Runner;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.JUnit4;
+import org.junit.runners.model.RunnerBuilder;
+
+/**
+ * Extends {@link AndroidAnnotatedBuilder} to add support for passing the
+ * {@link AndroidRunnerParams} object to the constructor of any {@link RunnerBuilder}
+ * implementation that is not a {@link BlockJUnit4ClassRunner}.
+ *
+ * <p>If {@link AndroidRunnerParams#isSkipExecution()} is {@code true} the super class will create
+ * a {@link RunnerBuilder} that will fire appropriate events as if the tests are being run but will
+ * not actually run the test. Unfortunately, when it does that it appears to assume that the runner
+ * extends {@link BlockJUnit4ClassRunner}, returns a skipping {@link RunnerBuilder} appropriate for
+ * that and ignores the actual {@code runnerClass}. That is a problem because it will not work for
+ * custom {@link RunnerBuilder} instances that do not extend {@link BlockJUnit4ClassRunner}.
+ *
+ * <p>Therefore, when skipping execution this does some additional checks to make sure that the
+ * {@code runnerClass} does extend {@link BlockJUnit4ClassRunner} before calling the overridden
+ * method.
+ *
+ * <p>It then attempts to construct a {@link RunnerBuilder} by calling the constructor with the
+ * signature {@code <init>(Class, AndroidRunnerParams)}. If that doesn't exist it falls back to
+ * the overridden behavior.
+ */
+class ExtendedAndroidAnnotatedBuilder extends AndroidAnnotatedBuilder {
+
+    private final AndroidRunnerParams runnerParams;
+
+    public ExtendedAndroidAnnotatedBuilder(RunnerBuilder suiteBuilder,
+            AndroidRunnerParams runnerParams) {
+        super(suiteBuilder, runnerParams);
+        this.runnerParams = runnerParams;
+    }
+
+    @Override
+    public Runner runnerForClass(Class<?> testClass) throws Exception {
+
+        RunWith annotation = testClass.getAnnotation(RunWith.class);
+        if (annotation != null) {
+            Class<? extends Runner> runnerClass = annotation.value();
+
+            // If the runner is expected to skip execution and it is a JUnit4, AndroidJUnit4 or
+            // a JUnit3 test class then return a special skipping runner.
+            if (runnerParams.isSkipExecution()) {
+                if (runnerClass == AndroidJUnit4.class || runnerClass == JUnit4.class
+                        || TestCase.class.isAssignableFrom(testClass)) {
+                    return super.runnerForClass(testClass);
+                }
+            }
+
+            try {
+                // try to build an AndroidJUnit4 runner
+                Runner runner = buildAndroidRunner(runnerClass, testClass);
+                if (runner != null) {
+                    return runner;
+                }
+            } catch (NoSuchMethodException e) {
+                // let the super class handle the error for us and throw an InitializationError
+                // exception.
+                return super.buildRunner(runnerClass, testClass);
+            }
+        }
+
+        return null;
+    }
+}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidRunnerBuilder.java b/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidRunnerBuilder.java
new file mode 100644
index 0000000..ed16318
--- /dev/null
+++ b/tests/core/runner/src/com/android/cts/core/runner/support/ExtendedAndroidRunnerBuilder.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.core.runner.support;
+
+import android.support.test.internal.runner.junit4.AndroidAnnotatedBuilder;
+import android.support.test.internal.util.AndroidRunnerParams;
+import org.junit.internal.builders.AnnotatedBuilder;
+import org.junit.runners.model.RunnerBuilder;
+
+/**
+ * Extends {@link AndroidRunnerBuilder} in order to provide alternate {@link RunnerBuilder}
+ * implementations.
+ */
+public class ExtendedAndroidRunnerBuilder extends AndroidRunnerBuilder {
+
+    private final AndroidAnnotatedBuilder mAndroidAnnotatedBuilder;
+
+    /**
+     * @param runnerParams {@link AndroidRunnerParams} that stores common runner parameters
+     */
+    public ExtendedAndroidRunnerBuilder(AndroidRunnerParams runnerParams) {
+        super(runnerParams);
+        mAndroidAnnotatedBuilder = new ExtendedAndroidAnnotatedBuilder(this, runnerParams);
+    }
+
+    @Override
+    protected AnnotatedBuilder annotatedBuilder() {
+        return mAndroidAnnotatedBuilder;
+    }
+}
diff --git a/tests/core/runner/src/com/android/cts/core/runner/support/package-info.java b/tests/core/runner/src/com/android/cts/core/runner/support/package-info.java
new file mode 100644
index 0000000..3ccec3c
--- /dev/null
+++ b/tests/core/runner/src/com/android/cts/core/runner/support/package-info.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Contains all the changes needed to the {@code android.support.test.internal.runner} classes.
+ *
+ * <p>As its name suggests {@code android.support.test.internal.runner} are internal classes that
+ * are not designed to be extended from outside those packages. This package encapsulates all the
+ * workarounds needed to overcome that limitation, from duplicating classes to using reflection.
+ * The intention is that these changes are temporary and they (or a better equivalent) will be
+ * quickly integrated into the internal classes.
+ */
+package com.android.cts.core.runner.support;
diff --git a/tests/sample/AndroidTest.xml b/tests/sample/AndroidTest.xml
index 86bc616..ae790fb 100644
--- a/tests/sample/AndroidTest.xml
+++ b/tests/sample/AndroidTest.xml
@@ -14,12 +14,6 @@
      limitations under the License.
 -->
 <configuration description="Config for CTS Sample test cases">
-    <target_preparer class=
-        "com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
-        <option name="target" value="device" />
-        <option name="config-filename" value="CtsSampleDeviceTestCases" />
-        <option name="version" value="1.0" />
-    </target_preparer>
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsSampleDeviceTestCases.apk" />
diff --git a/tests/sample/DynamicConfig.xml b/tests/sample/DynamicConfig.xml
deleted file mode 100644
index 515dc01..0000000
--- a/tests/sample/DynamicConfig.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<dynamicConfig>
-    <entry key="report-log-name">
-        <value>SampleTestMetrics</value>
-    </entry>
-    <entry key="testMultiplication-stream-name">
-        <value>testMultiplicationMetrics</value>
-    </entry>
-    <entry key="testCountUp-stream-name">
-        <value>testCountUpMetrics</value>
-    </entry>
-    <entry key="testCountDown-stream-name">
-        <value>testCountDownMetrics</value>
-    </entry>
-    <entry key="testSort-stream-name">
-        <value>testSortMetrics</value>
-    </entry>
-</dynamicConfig>
\ No newline at end of file
diff --git a/tests/sample/src/android/sample/cts/SampleDeviceReportLogTest.java b/tests/sample/src/android/sample/cts/SampleDeviceReportLogTest.java
index 8985bd6..7f8e2f6 100644
--- a/tests/sample/src/android/sample/cts/SampleDeviceReportLogTest.java
+++ b/tests/sample/src/android/sample/cts/SampleDeviceReportLogTest.java
@@ -19,7 +19,6 @@
 import android.test.ActivityInstrumentationTestCase2;
 
 import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.DynamicConfigDeviceSide;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
 
@@ -32,16 +31,6 @@
         extends ActivityInstrumentationTestCase2<SampleDeviceActivity> {
 
     /**
-     * The default name for metrics report log file.
-     */
-    private String DEFAULT_REPORT_LOG_NAME = "DefaultMetrics";
-
-    /**
-     * The default name for a metrics stream.
-     */
-    private String DEFAULT_STREAM_NAME = "DefaultStream";
-
-    /**
      * Sample numbers used by the sample tests.
      */
     private static final int MULTIPLICATION_NUMBER_1 = 23;
@@ -50,10 +39,10 @@
     private static final int COUNT_START = 1;
     private static final int COUNT_END = 1000;
 
-    private static final String EXPECTED_PRODUCT_TAG = "Expected Product";
-    private static final String ACTUAL_PRODUCT_TAG = "Actual Product";
-    private static final String START_TAG = "Count Start";
-    private static final String END_TAG = "Actual End";
+    private static final String EXPECTED_PRODUCT_TAG = "expected_product";
+    private static final String ACTUAL_PRODUCT_TAG = "actual_product";
+    private static final String START_TAG = "count_start";
+    private static final String END_TAG = "actual_end";
 
     /**
      * Constructor which passes the class of the activity to be instrumented.
@@ -71,8 +60,8 @@
         assertTrue("Multiplication result do not match", product == MULTIPLICATION_RESULT);
 
         // Log metrics from the test.
-        String reportLogName = getReportLogName();
-        String streamName = getStreamName("testMultiplication-stream-name");
+        String reportLogName = "SampleDeviceTestMetrics";
+        String streamName = "test_multiplication_metrics";
         DeviceReportLog reportLog = new DeviceReportLog(reportLogName, streamName);
         reportLog.addValue(EXPECTED_PRODUCT_TAG, 1.0 * MULTIPLICATION_RESULT, ResultType.NEUTRAL,
                 ResultUnit.NONE);
@@ -85,7 +74,7 @@
      * Sample test to check counting up.
      */
     public void testCountUp() {
-        String streamName = getStreamName("testCountUp-stream-name");
+        String streamName = "test_count_up_metrics";
         countHelper(1, streamName);
     }
 
@@ -93,7 +82,7 @@
      * Sample test to check counting down.
      */
     public void testCountDown() {
-        String streamName = getStreamName("testCountDown-stream-name");
+        String streamName = "test_count_down_metrics";
         countHelper(2, streamName);
     }
 
@@ -122,45 +111,11 @@
         }
 
         // Log metrics.
-        String reportLogName = getReportLogName();
+        String reportLogName = "SampleDeviceTestMetrics";
         DeviceReportLog reportLog = new DeviceReportLog(reportLogName, streamName);
-        reportLog.addValue(streamName + START_TAG, 1.0 * start, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.addValue(streamName + END_TAG, 1.0 * end, ResultType.NEUTRAL, ResultUnit.NONE);
-        reportLog.setSummary(streamName + END_TAG, 1.0 * end, ResultType.NEUTRAL, ResultUnit.NONE);
+        reportLog.addValue(START_TAG, 1.0 * start, ResultType.NEUTRAL, ResultUnit.NONE);
+        reportLog.addValue(END_TAG, 1.0 * end, ResultType.NEUTRAL, ResultUnit.NONE);
+        reportLog.setSummary(END_TAG, 1.0 * end, ResultType.NEUTRAL, ResultUnit.NONE);
         reportLog.submit(getInstrumentation());
     }
-
-    /**
-     * Retreives name of report log from dynamic config.
-     *
-     * @return {@link String} name of the report log.
-     */
-    private String getReportLogName() {
-        try {
-            DynamicConfigDeviceSide dynamicConfig = new DynamicConfigDeviceSide(
-                    "CtsSampleDeviceTestCases");
-            return dynamicConfig.getValues("report-log-name").get(0);
-        } catch (Exception e) {
-            // Do nothing.
-        }
-        return DEFAULT_REPORT_LOG_NAME ;
-    }
-
-
-    /**
-     * Retreives name of metrics stream from dynamic config.
-     *
-     * @param key The key in dynamic config containing stream name.
-     * @return {@link String} name of the stream.
-     */
-    private String getStreamName(String key) {
-        try {
-            DynamicConfigDeviceSide dynamicConfig = new DynamicConfigDeviceSide(
-                    "CtsSampleDeviceTestCases");
-            return dynamicConfig.getValues(key).get(0);
-        } catch (Exception e) {
-            // Do nothing.
-        }
-        return DEFAULT_STREAM_NAME ;
-    }
 }
diff --git a/tests/sample/src/android/sample/cts/SampleDeviceResultTest.java b/tests/sample/src/android/sample/cts/SampleDeviceResultTest.java
index 2f6ce78..f8f7a6b 100644
--- a/tests/sample/src/android/sample/cts/SampleDeviceResultTest.java
+++ b/tests/sample/src/android/sample/cts/SampleDeviceResultTest.java
@@ -19,7 +19,6 @@
 import android.test.ActivityInstrumentationTestCase2;
 
 import com.android.compatibility.common.util.DeviceReportLog;
-import com.android.compatibility.common.util.DynamicConfigDeviceSide;
 import com.android.compatibility.common.util.MeasureRun;
 import com.android.compatibility.common.util.MeasureTime;
 import com.android.compatibility.common.util.ResultType;
@@ -37,16 +36,6 @@
 public class SampleDeviceResultTest extends ActivityInstrumentationTestCase2<SampleDeviceActivity> {
 
     /**
-     * The default name for metrics report log file.
-     */
-    private String DEFAULT_REPORT_LOG_NAME = "DefaultMetrics";
-
-    /**
-     * The default name for a metrics stream.
-     */
-    private String DEFAULT_STREAM_NAME = "DefaultStream";
-
-    /**
      * The number of times to repeat the test.
      */
     private static final int REPEAT = 5;
@@ -87,15 +76,15 @@
         // Compute the stats.
         Stat.StatResult stat = Stat.getStat(result);
         // Create a new report to hold the metrics.
-        String reportLogName = getReportLogName();
-        String streamName = getStreamName("testSort-stream-name");
+        String reportLogName = "SampleDeviceTestMetrics";
+        String streamName = "test_sort_metrics";
         DeviceReportLog reportLog = new DeviceReportLog(reportLogName, streamName);
         // Add the results to the report.
-        reportLog.addValues("Times", result, ResultType.LOWER_BETTER, ResultUnit.MS);
-        reportLog.addValue("Min", stat.mMin, ResultType.LOWER_BETTER, ResultUnit.MS);
-        reportLog.addValue("Max", stat.mMax, ResultType.LOWER_BETTER, ResultUnit.MS);
+        reportLog.addValues("times", result, ResultType.LOWER_BETTER, ResultUnit.MS);
+        reportLog.addValue("min", stat.mMin, ResultType.LOWER_BETTER, ResultUnit.MS);
+        reportLog.addValue("max", stat.mMax, ResultType.LOWER_BETTER, ResultUnit.MS);
         // Every report must have a summary,
-        reportLog.setSummary("Average", stat.mAverage, ResultType.LOWER_BETTER, ResultUnit.MS);
+        reportLog.setSummary("average", stat.mAverage, ResultType.LOWER_BETTER, ResultUnit.MS);
         // Submit the report to the given instrumentation.
         reportLog.submit(getInstrumentation());
     }
@@ -123,39 +112,4 @@
         }
         return true;
     }
-
-    /**
-     * Retreives name of report log from dynamic config.
-     *
-     * @return {@link String} name of the report log.
-     */
-    private String getReportLogName() {
-        try {
-            DynamicConfigDeviceSide dynamicConfig = new DynamicConfigDeviceSide(
-                    "CtsSampleDeviceTestCases");
-            return dynamicConfig.getValues("report-log-name").get(0);
-        } catch (Exception e) {
-            // Do nothing.
-        }
-        return DEFAULT_REPORT_LOG_NAME;
-    }
-
-    /**
-     * Retreives name of metrics stream from dynamic config.
-     *
-     * @param key The key in dynamic config containing stream name.
-     * @return {@link String} name of the stream.
-     */
-    private String getStreamName(String key) {
-        try {
-            DynamicConfigDeviceSide dynamicConfig = new DynamicConfigDeviceSide(
-                    "CtsSampleDeviceTestCases");
-            return dynamicConfig.getValues(key).get(0);
-        } catch (Exception e) {
-            // Do nothing.
-        }
-        return DEFAULT_STREAM_NAME ;
-    }
-
-
 }
diff --git a/tests/tests/app/Android.mk b/tests/tests/app/Android.mk
new file mode 100644
index 0000000..08201a6
--- /dev/null
+++ b/tests/tests/app/Android.mk
@@ -0,0 +1,36 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsAndroidAppTestCases
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+
+# and when built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/app/AndroidManifest.xml b/tests/tests/app/AndroidManifest.xml
new file mode 100644
index 0000000..be903e3
--- /dev/null
+++ b/tests/tests/app/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.app.cts">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+
+        <activity android:name=".ApplyOverrideConfigurationActivity"
+                  android:configChanges="orientation|screenSize" />
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.app.cts"
+                     android:label="CTS tests of android.app">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
+
diff --git a/tests/tests/app/AndroidTest.xml b/tests/tests/app/AndroidTest.xml
new file mode 100644
index 0000000..739e0ba
--- /dev/null
+++ b/tests/tests/app/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Configuration for app Tests">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsAndroidAppTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.app.cts" />
+        <option name="runtime-hint" value="1s" />
+    </test>
+</configuration>
diff --git a/tests/tests/app/src/android/app/cts/ApplyOverrideConfigurationActivity.java b/tests/tests/app/src/android/app/cts/ApplyOverrideConfigurationActivity.java
new file mode 100644
index 0000000..305d0a8
--- /dev/null
+++ b/tests/tests/app/src/android/app/cts/ApplyOverrideConfigurationActivity.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.app.cts;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Configuration;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Future;
+
+public class ApplyOverrideConfigurationActivity extends Activity {
+    public static final int OVERRIDE_SMALLEST_WIDTH = 99999;
+
+    private CompletableFuture<Configuration> mOnConfigurationChangedFuture = null;
+
+    @Override
+    protected void attachBaseContext(Context newBase) {
+        super.attachBaseContext(newBase);
+
+        final Configuration overrideConfig = new Configuration();
+        overrideConfig.smallestScreenWidthDp = OVERRIDE_SMALLEST_WIDTH;
+        applyOverrideConfiguration(overrideConfig);
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+
+        synchronized (this) {
+            if (mOnConfigurationChangedFuture != null) {
+                mOnConfigurationChangedFuture.complete(new Configuration(newConfig));
+                mOnConfigurationChangedFuture = null;
+            }
+        }
+    }
+
+    /**
+     * Hands back a Future that will be completed when onConfigurationChanged() is called.
+     * It will only report a single call to onConfigurationChanged(). Subsequent calls can be
+     * captured by calling this method again. Calling this method will cancel all past
+     * Futures received from this method.
+     * @return A Future that completes with the configuration passed in to onConfigurationChanged().
+     */
+    public synchronized Future<Configuration> watchForSingleOnConfigurationChangedCallback() {
+        if (mOnConfigurationChangedFuture != null) {
+            mOnConfigurationChangedFuture.cancel(true);
+        }
+
+        mOnConfigurationChangedFuture = new CompletableFuture<>();
+        return mOnConfigurationChangedFuture;
+    }
+}
diff --git a/tests/tests/app/src/android/app/cts/ApplyOverrideConfigurationTest.java b/tests/tests/app/src/android/app/cts/ApplyOverrideConfigurationTest.java
new file mode 100644
index 0000000..a8f1473
--- /dev/null
+++ b/tests/tests/app/src/android/app/cts/ApplyOverrideConfigurationTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.app.cts;
+
+import android.app.UiAutomation;
+import android.content.res.Configuration;
+import android.support.test.filters.SmallTest;
+import android.test.ActivityInstrumentationTestCase2;
+
+import java.util.concurrent.Future;
+
+/**
+ * Tests the {@link android.view.ContextThemeWrapper#applyOverrideConfiguration(Configuration)}
+ * method and how it affects the Activity's resources and lifecycle callbacks.
+ */
+public class ApplyOverrideConfigurationTest extends
+        ActivityInstrumentationTestCase2<ApplyOverrideConfigurationActivity> {
+    public ApplyOverrideConfigurationTest() {
+        super(ApplyOverrideConfigurationActivity.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE);
+        super.tearDown();
+    }
+
+    @SmallTest
+    public void testOverriddenConfigurationIsPassedIntoCallback() throws Exception {
+        final Configuration config = getActivity().getResources().getConfiguration();
+        final int originalOrientation = config.orientation;
+        assertEquals(ApplyOverrideConfigurationActivity.OVERRIDE_SMALLEST_WIDTH,
+                config.smallestScreenWidthDp);
+
+        Future<Configuration> callback =
+                getActivity().watchForSingleOnConfigurationChangedCallback();
+
+        getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_90);
+
+        final Configuration callbackConfig = callback.get();
+        assertNotNull(callbackConfig);
+
+        final Configuration newConfig = getActivity().getResources().getConfiguration();
+        assertTrue(newConfig.orientation != originalOrientation);
+        assertEquals(ApplyOverrideConfigurationActivity.OVERRIDE_SMALLEST_WIDTH,
+                newConfig.smallestScreenWidthDp);
+
+        assertEquals(newConfig, callbackConfig);
+    }
+}
diff --git a/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java b/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
index c21bc9c..d0a00c9 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
@@ -79,7 +79,7 @@
         }
     }
 
-    public void testAssistStructure() throws Exception {
+    public void testAssistStructure() throws Throwable {
         if (mActivityManager.isLowRamDevice()) {
             Log.d(TAG, "Not running assist tests on low-RAM device.");
             return;
@@ -90,10 +90,14 @@
         waitForOnResume();
         startSession();
         waitForContext();
-        verifyAssistDataNullness(false, false, false, false);
-
-        verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE),
-                false /*FLAG_SECURE set*/);
+        getInstrumentation().waitForIdleSync();
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                verifyAssistDataNullness(false, false, false, false);
+                verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE), false /*FLAG_SECURE set*/);
+            }
+        });
     }
 
     private class AssistStructureTestBroadcastReceiver extends BroadcastReceiver {
diff --git a/tests/tests/content/src/android/content/cts/ContextTest.java b/tests/tests/content/src/android/content/cts/ContextTest.java
index 4cb85cc..0d9c56d 100644
--- a/tests/tests/content/src/android/content/cts/ContextTest.java
+++ b/tests/tests/content/src/android/content/cts/ContextTest.java
@@ -27,15 +27,19 @@
 import android.database.sqlite.SQLiteDatabase;
 import android.test.AndroidTestCase;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.util.Xml;
 import android.view.WindowManager;
 
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 
 public class ContextTest extends AndroidTestCase {
+    private static final String TAG = "ContextTest";
+
     private Context mContext;
 
     @Override
@@ -303,6 +307,44 @@
         assertEquals(0xffffff00, color);
     }
 
+    /**
+     * Developers have come to expect at least ext4-style filename behavior, so
+     * verify that the underlying filesystem supports them.
+     */
+    public void testFilenames() throws Exception {
+        final File base = mContext.getFilesDir();
+        assertValidFile(new File(base, "foo"));
+        assertValidFile(new File(base, ".bar"));
+        assertValidFile(new File(base, "foo.bar"));
+        assertValidFile(new File(base, "\u2603"));
+        assertValidFile(new File(base, "\uD83D\uDCA9"));
+
+        final int pid = android.os.Process.myPid();
+        final StringBuilder sb = new StringBuilder(255);
+        while (sb.length() <= 255) {
+            sb.append(pid);
+            sb.append(mContext.getPackageName());
+        }
+        sb.setLength(255);
+
+        final String longName = sb.toString();
+        final File longDir = new File(base, longName);
+        assertValidFile(longDir);
+        longDir.mkdir();
+        final File longFile = new File(longDir, longName);
+        assertValidFile(longFile);
+    }
+
+    private void assertValidFile(File file) throws Exception {
+        Log.d(TAG, "Checking " + file);
+        assertTrue("Failed to create " + file, file.createNewFile());
+        assertTrue("Doesn't exist after create " + file, file.exists());
+        assertTrue("Failed to delete after create " + file, file.delete());
+        new FileOutputStream(file).close();
+        assertTrue("Doesn't exist after stream " + file, file.exists());
+        assertTrue("Failed to delete after stream " + file, file.delete());
+    }
+
     private AttributeSet getAttributeSet(int resourceId) {
         final XmlResourceParser parser = getContext().getResources().getXml(
                 resourceId);
diff --git a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
index dcd350e..aa8348a 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
@@ -1189,6 +1189,13 @@
                 assertEquals(0.0f, width);
             }
             {
+                for (int i = 0; i < string.length(); i++) {
+                    final float width = p.getRunAdvance(string, i, i + 1, 0, string.length(),
+                            false, i);
+                    assertEquals(0.0f, width);
+                }
+            }
+            {
                 final float widthToMid = p.getRunAdvance(string, 0, string.length(), 0,
                         string.length(), false, string.length() / 2);
                 final float widthToTail = p.getRunAdvance(string, 0, string.length(), 0,
@@ -1203,11 +1210,32 @@
                         string.length(), false, string.length());
                 assertTrue(widthFromHead > widthFromSecond);
             }
+            {
+                float width = 0.0f;
+                for (int i = 0; i < string.length(); i++) {
+                    width += p.getRunAdvance(string, i, i + 1, 0, string.length(), false, i + 1);
+                }
+                final float totalWidth = p.getRunAdvance(string, 0, string.length(), 0,
+                        string.length(), false, string.length());
+                assertEquals(totalWidth, width, 1.0f);
+            }
         }
         {
             // RTL
             String string = "\u0644\u063A\u0629 \u0639\u0631\u0628\u064A\u0629"; // Arabic
             {
+                final float width = p.getRunAdvance(string, 0, string.length(), 0,
+                        string.length(), true, 0);
+                assertEquals(0.0f, width);
+            }
+            {
+                for (int i = 0; i < string.length(); i++) {
+                    final float width = p.getRunAdvance(string, i, i + 1, 0, string.length(),
+                            true, i);
+                    assertEquals(0.0f, width);
+                }
+            }
+            {
                 final float widthToMid = p.getRunAdvance(string, 0, string.length(), 0,
                         string.length(), true, string.length() / 2);
                 final float widthToTail = p.getRunAdvance(string, 0, string.length(), 0,
diff --git a/tests/tests/icu/Android.mk b/tests/tests/icu/Android.mk
index 39a4b53..6f183d5 100644
--- a/tests/tests/icu/Android.mk
+++ b/tests/tests/icu/Android.mk
@@ -31,9 +31,7 @@
 # The aim of this package is to run tests against the implementation in use by
 # the current android system.
 LOCAL_STATIC_JAVA_LIBRARIES := \
-	compatibility-device-util \
-	android-support-test \
-	vogarexpect \
+	cts-core-test-runner \
 	android-icu4j-tests
 
 # Tag this module as a cts test artifact
diff --git a/tests/tests/icu/AndroidManifest.xml b/tests/tests/icu/AndroidManifest.xml
index 7d99c0a..c743375 100644
--- a/tests/tests/icu/AndroidManifest.xml
+++ b/tests/tests/icu/AndroidManifest.xml
@@ -22,7 +22,7 @@
         <uses-library android:name="android.test.runner" />
     </application>
 
-    <instrumentation android:name="android.icu.cts.IcuTestRunner"
+    <instrumentation android:name="com.android.cts.core.runner.CoreTestRunner"
                      android:targetPackage="android.icu.cts"
-                     android:label="ICU4J library tests."/>
+                     android:label="CTS Repackaged ICU4J library tests."/>
 </manifest>
diff --git a/tests/tests/icu/AndroidTest.xml b/tests/tests/icu/AndroidTest.xml
index 18c95cd..769b789 100644
--- a/tests/tests/icu/AndroidTest.xml
+++ b/tests/tests/icu/AndroidTest.xml
@@ -18,8 +18,13 @@
         <option name="test-file-name" value="CtsIcuTestCases.apk" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="runner" value="android.icu.cts.IcuTestRunner" /><!-- override AJUR -->
+        <!-- override AJUR -->
+        <option name="runner" value="com.android.cts.core.runner.CoreTestRunner" />
         <option name="package" value="android.icu.cts" />
+        <option name="instrumentation-arg" key="core-root-classes"
+                value="android.icu.cts.coverage.TestAll,android.icu.dev.test.TestAll" />
+        <option name="instrumentation-arg" key="core-expectations"
+                value="/android/icu/cts/expectations/icu-known-failures.txt" />
         <option name="runtime-hint" value="30m19s" />
     </test>
 </configuration>
diff --git a/tests/tests/icu/test-list.txt b/tests/tests/icu/test-list.txt
index 84da3c4..cd47a76 100644
--- a/tests/tests/icu/test-list.txt
+++ b/tests/tests/icu/test-list.txt
@@ -1,3 +1,37 @@
+android.icu.cts.coverage.lang.UCharacterTest#testNameAliasing
+android.icu.cts.coverage.lang.UCharacterTest#testToTitleCase_Locale_String_BreakIterator_I
+android.icu.cts.coverage.lang.UCharacterTest#testToTitleCase_String_BreakIterator_en
+android.icu.cts.coverage.lang.UCharacterTest#testToTitleCase_String_BreakIterator_nl
+android.icu.cts.coverage.text.AlphabeticIndexTest#testAddLabels_Locale
+android.icu.cts.coverage.text.AlphabeticIndexTest#testFlowLabels
+android.icu.cts.coverage.text.AlphabeticIndexTest#testGetRecordCount_empty
+android.icu.cts.coverage.text.AlphabeticIndexTest#testGetRecordCount_withRecords
+android.icu.cts.coverage.text.DateFormatSymbolsTest#testSetEraNames_defensivelyCopies
+android.icu.cts.coverage.text.DateFormatSymbolsTest#testYearNames_defensivelyCopies
+android.icu.cts.coverage.text.DateIntervalFormatTest#testGetInstance_String_DateIntervalInfo
+android.icu.cts.coverage.text.DateIntervalFormatTest#testGetInstance_String_Locale_DateIntervalInfo
+android.icu.cts.coverage.text.DateIntervalFormatTest#testParseObject_notSupported
+android.icu.cts.coverage.text.LocaleDisplayNamesTest#testGetInstance
+android.icu.cts.coverage.text.LocaleDisplayNamesTest#testGetLocale
+android.icu.cts.coverage.text.LocaleDisplayNamesTest#testKeyDisplayName
+android.icu.cts.coverage.text.LocaleDisplayNamesTest#testKeyValueDisplayName
+android.icu.cts.coverage.text.LocaleDisplayNamesTest#testLocaleDisplayName
+android.icu.cts.coverage.text.LocaleDisplayNamesTest#testScriptDisplayName_Int
+android.icu.cts.coverage.text.LocaleDisplayNamesTest#testScriptDisplayName_String
+android.icu.cts.coverage.text.LocaleDisplayNamesTest#testVariantDisplayName
+android.icu.cts.coverage.text.RelativeDateTimeFormatterTest#testGetInstance
+android.icu.cts.coverage.text.TimeZoneNamesTest#testGetAvailableMetaZoneIDs
+android.icu.cts.coverage.text.TimeZoneNamesTest#testGetAvailableMetaZoneIDs_String
+android.icu.cts.coverage.text.TimeZoneNamesTest#testGetInstance_Locale
+android.icu.cts.coverage.text.TimeZoneNamesTest#testGetMetaZoneDisplayName
+android.icu.cts.coverage.text.TimeZoneNamesTest#testGetMetaZoneID
+android.icu.cts.coverage.text.TimeZoneNamesTest#testGetTimeZoneDisplayName
+android.icu.cts.coverage.text.UnicodeSetTest#testAddAll_CharacterSequences
+android.icu.cts.coverage.text.UnicodeSetTest#testCompareTo
+android.icu.cts.coverage.util.CurrencyTest#testGetDefaultFractionDigits_CurrencyUsage
+android.icu.cts.coverage.util.CurrencyTest#testGetName_Locale_Int_String_BooleanArray
+android.icu.cts.coverage.util.CurrencyTest#testGetRoundingIncrement
+android.icu.cts.coverage.util.CurrencyTest#testGetRoundingIncrement_CurrencyUsage
 android.icu.dev.test.bidi.BiDiConformanceTest#TestBidiCharacterTest
 android.icu.dev.test.bidi.BiDiConformanceTest#TestBidiTest
 android.icu.dev.test.bidi.TestBidi#testBidi
@@ -164,6 +198,7 @@
 android.icu.dev.test.calendar.IBMCalendarTest#TestLeapFieldDifference
 android.icu.dev.test.calendar.IBMCalendarTest#TestMalaysianInstance
 android.icu.dev.test.calendar.IBMCalendarTest#TestRepeatedWallTime
+android.icu.dev.test.calendar.IBMCalendarTest#TestSimpleDateFormatCoverage
 android.icu.dev.test.calendar.IBMCalendarTest#TestSkippedWallTime
 android.icu.dev.test.calendar.IBMCalendarTest#TestTaiwan
 android.icu.dev.test.calendar.IBMCalendarTest#TestTaiwanCoverage
@@ -178,6 +213,7 @@
 android.icu.dev.test.calendar.IndianTest#TestBasic
 android.icu.dev.test.calendar.IndianTest#TestCases
 android.icu.dev.test.calendar.IndianTest#TestCoverage
+android.icu.dev.test.calendar.IndianTest#TestCoverage12424
 android.icu.dev.test.calendar.IndianTest#TestLimits
 android.icu.dev.test.calendar.IndianTest#TestYear
 android.icu.dev.test.calendar.IndianTest#TestYearEdge
@@ -198,6 +234,7 @@
 android.icu.dev.test.calendar.JapaneseTest#TestCoverage
 android.icu.dev.test.calendar.JapaneseTest#TestJapaneseYear3282
 android.icu.dev.test.calendar.JapaneseTest#TestLimits
+android.icu.dev.test.calendar.PersianTest#TestCoverage12424
 android.icu.dev.test.calendar.PersianTest#TestMapping
 android.icu.dev.test.charsetdet.TestCharsetDetector#TestArabic
 android.icu.dev.test.charsetdet.TestCharsetDetector#TestBufferOverflow
@@ -875,6 +912,7 @@
 android.icu.dev.test.format.MeasureUnitTest#testOldFormatBadArg
 android.icu.dev.test.format.MeasureUnitTest#testOldFormatWithArray
 android.icu.dev.test.format.MeasureUnitTest#testOldFormatWithList
+android.icu.dev.test.format.MeasureUnitTest#testParseObject
 android.icu.dev.test.format.MeasureUnitTest#TestSerial
 android.icu.dev.test.format.MeasureUnitTest#TestSerialFormatWidthEnum
 android.icu.dev.test.format.MeasureUnitTest#testSimplePer
@@ -969,6 +1007,7 @@
 android.icu.dev.test.format.NumberFormatTest#TestFieldPositionFractionButInteger
 android.icu.dev.test.format.NumberFormatTest#TestFieldPositionInteger
 android.icu.dev.test.format.NumberFormatTest#TestFormat
+android.icu.dev.test.format.NumberFormatTest#TestFormatAbstractImplCoverage
 android.icu.dev.test.format.NumberFormatTest#TestFormatToCharacterIteratorIssue11805
 android.icu.dev.test.format.NumberFormatTest#TestFormatToCharacterIteratorThread
 android.icu.dev.test.format.NumberFormatTest#TestGetAvailableLocales
@@ -983,6 +1022,7 @@
 android.icu.dev.test.format.NumberFormatTest#TestNegZeroRounding
 android.icu.dev.test.format.NumberFormatTest#TestNumberFormatFactory
 android.icu.dev.test.format.NumberFormatTest#TestNumberFormatTestTupleToString
+android.icu.dev.test.format.NumberFormatTest#TestNumberingSystemCoverage
 android.icu.dev.test.format.NumberFormatTest#TestNumberingSystems
 android.icu.dev.test.format.NumberFormatTest#TestPad
 android.icu.dev.test.format.NumberFormatTest#TestParse
@@ -1101,6 +1141,7 @@
 android.icu.dev.test.format.PluralFormatUnitTest#TestApplyPatternAndFormat
 android.icu.dev.test.format.PluralFormatUnitTest#TestConstructor
 android.icu.dev.test.format.PluralFormatUnitTest#TestDecimals
+android.icu.dev.test.format.PluralFormatUnitTest#TestEquals
 android.icu.dev.test.format.PluralFormatUnitTest#TestExtendedPluralFormat
 android.icu.dev.test.format.PluralFormatUnitTest#TestExtendedPluralFormatParsing
 android.icu.dev.test.format.PluralFormatUnitTest#TestNegative
@@ -1242,6 +1283,11 @@
 android.icu.dev.test.format.TestMessageFormat#TestFormatToCharacterIterator
 android.icu.dev.test.format.TestMessageFormat#TestGetFormatByArgumentName
 android.icu.dev.test.format.TestMessageFormat#TestHashCode
+android.icu.dev.test.format.TestMessageFormat#TestMessagePatternAutoQuoteApostropheDeep
+android.icu.dev.test.format.TestMessageFormat#TestMessagePatternFreezable
+android.icu.dev.test.format.TestMessageFormat#TestMessagePatternNamedAndNumberedArguments
+android.icu.dev.test.format.TestMessageFormat#TestMessagePatternParseChoiceStyle
+android.icu.dev.test.format.TestMessageFormat#TestMessagePatternPartCoverage
 android.icu.dev.test.format.TestMessageFormat#TestMsgFormatChoice
 android.icu.dev.test.format.TestMessageFormat#testNamedArguments
 android.icu.dev.test.format.TestMessageFormat#testNestedFormatsInPluralFormat
@@ -1282,10 +1328,13 @@
 android.icu.dev.test.format.TimeUnitTest#TestSetup
 android.icu.dev.test.format.TimeUnitTest#TestStandInForMeasureFormat
 android.icu.dev.test.format.TimeUnitTest#TestTimeUnitFormat
+android.icu.dev.test.format.TimeZoneFormatTest#TestAPI
 android.icu.dev.test.format.TimeZoneFormatTest#TestFormat
 android.icu.dev.test.format.TimeZoneFormatTest#TestFormatTZDBNames
+android.icu.dev.test.format.TimeZoneFormatTest#TestInheritedFormat
 android.icu.dev.test.format.TimeZoneFormatTest#TestISOFormat
 android.icu.dev.test.format.TimeZoneFormatTest#TestParse
+android.icu.dev.test.format.TimeZoneFormatTest#TestParseCoverage
 android.icu.dev.test.format.TimeZoneFormatTest#TestTimeRoundTrip
 android.icu.dev.test.format.TimeZoneFormatTest#TestTimeZoneRoundTrip
 android.icu.dev.test.format.TimeZoneFormatTest#TestTZDBNamesThreading
@@ -1482,6 +1531,7 @@
 android.icu.dev.test.normalizer.BasicTest#TestDebugStatic
 android.icu.dev.test.normalizer.BasicTest#TestDecomp
 android.icu.dev.test.normalizer.BasicTest#TestExplodingBase
+android.icu.dev.test.normalizer.BasicTest#TestFCD
 android.icu.dev.test.normalizer.BasicTest#TestFCNFKCClosure
 android.icu.dev.test.normalizer.BasicTest#TestFilteredAppend
 android.icu.dev.test.normalizer.BasicTest#TestFilteredNormalizer2
@@ -1492,7 +1542,11 @@
 android.icu.dev.test.normalizer.BasicTest#TestGetRawDecomposition
 android.icu.dev.test.normalizer.BasicTest#TestHangulCompose
 android.icu.dev.test.normalizer.BasicTest#TestHangulDecomp
+android.icu.dev.test.normalizer.BasicTest#TestNFC
+android.icu.dev.test.normalizer.BasicTest#TestNFD
 android.icu.dev.test.normalizer.BasicTest#TestNone
+android.icu.dev.test.normalizer.BasicTest#TestNoneNormalizer
+android.icu.dev.test.normalizer.BasicTest#TestNoopNormalizer2
 android.icu.dev.test.normalizer.BasicTest#TestNormalizerAPI
 android.icu.dev.test.normalizer.BasicTest#TestPreviousNext
 android.icu.dev.test.normalizer.BasicTest#TestPreviousNextJCI
@@ -2156,7 +2210,10 @@
 android.icu.dev.test.util.ULocaleTest#TestCoverage
 android.icu.dev.test.util.ULocaleTest#TestDateFormat
 android.icu.dev.test.util.ULocaleTest#TestDisplayKeyword
+android.icu.dev.test.util.ULocaleTest#TestDisplayLanguageWithDialectCoverage
 android.icu.dev.test.util.ULocaleTest#TestDisplayNames
+android.icu.dev.test.util.ULocaleTest#TestDisplayNameWithDialectCoverage
+android.icu.dev.test.util.ULocaleTest#TestDisplayScriptCoverage
 android.icu.dev.test.util.ULocaleTest#TestDisplayWithKeyword
 android.icu.dev.test.util.ULocaleTest#TestExtension
 android.icu.dev.test.util.ULocaleTest#TestForLanguageTag
diff --git a/tests/tests/location/Android.mk b/tests/tests/location/Android.mk
index 842a92d..6a8b9d3 100644
--- a/tests/tests/location/Android.mk
+++ b/tests/tests/location/Android.mk
@@ -16,6 +16,29 @@
 
 include $(CLEAR_VARS)
 
+# Reusable Location test classes and helpers
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := cts-location-tests
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    ctsdeviceutil ctstestrunner
+
+LOCAL_SDK_VERSION := test_current
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src/android/location/cts)
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# CtsLocationTestCases package
+
+include $(CLEAR_VARS)
+
 # don't include this package in any target
 LOCAL_MODULE_TAGS := optional
 # and when built explicitly put it in the data partition
diff --git a/tests/tests/location/src/android/location/cts/GnssClockTest.java b/tests/tests/location/src/android/location/cts/GnssClockTest.java
index e2ac503..b883f74 100644
--- a/tests/tests/location/src/android/location/cts/GnssClockTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssClockTest.java
@@ -18,9 +18,8 @@
 
 import android.location.GnssClock;
 import android.os.Parcel;
-import android.test.AndroidTestCase;
 
-public class GnssClockTest extends AndroidTestCase {
+public class GnssClockTest extends GnssTestCase {
     public void testDescribeContents() {
         GnssClock clock = new GnssClock();
         clock.describeContents();
diff --git a/tests/tests/location/src/android/location/cts/GnssMeasurementRegistrationTest.java b/tests/tests/location/src/android/location/cts/GnssMeasurementRegistrationTest.java
index 00e0877..d3a310e 100644
--- a/tests/tests/location/src/android/location/cts/GnssMeasurementRegistrationTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssMeasurementRegistrationTest.java
@@ -19,7 +19,6 @@
 import android.location.GnssMeasurement;
 import android.location.GnssMeasurementsEvent;
 import android.location.GpsStatus;
-import android.test.AndroidTestCase;
 import android.util.Log;
 
 import java.util.List;
@@ -49,9 +48,9 @@
  *                  2.4.2 The test might fail in a future Android release, when this requirement
  *                        becomes mandatory.
  */
-public class GnssMeasurementRegistrationTest extends AndroidTestCase {
+public class GnssMeasurementRegistrationTest extends GnssTestCase {
 
-    private static final String TAG = "GpsMeasRegistrationTest";
+    private static final String TAG = "GnssMeasRegTest";
     private TestLocationManager mTestLocationManager;
     private static final int EVENTS_COUNT = 5;
     private static final int GPS_EVENTS_COUNT = 1;
@@ -93,7 +92,7 @@
         mMeasurementListener = new TestGnssMeasurementListener(TAG, GPS_EVENTS_COUNT);
         mTestLocationManager.registerGnssMeasurementCallback(mMeasurementListener);
 
-        assertTrue(mMeasurementListener.await());
+        mMeasurementListener.await();
         if (!mMeasurementListener.verifyState()) {
             return;
         }
@@ -114,8 +113,7 @@
         mTestLocationManager.requestLocationUpdates(mLocationListener);
 
         // Wait for location updates
-        assertTrue(mLocationListener.await());
-
+        mLocationListener.await();
         Log.i(TAG, "Location received = " + mLocationListener.isLocationReceived());
 
         // Register for Gps Status updates
@@ -123,8 +121,7 @@
         mTestLocationManager.addGpsStatusListener(mGpsStatusListener);
 
         // wait for Gps Status updates
-        assertTrue(mGpsStatusListener.await());
-
+        mGpsStatusListener.await();
         if (!mGpsStatusListener.isGpsStatusReceived()) {
             // Skip the Test. No Satellites are visible. Device may be Indoor
             Log.i(TAG, "No Satellites are visible. Device may be Indoor. Skipping Test.");
diff --git a/tests/tests/location/src/android/location/cts/GnssMeasurementTest.java b/tests/tests/location/src/android/location/cts/GnssMeasurementTest.java
index 3ae7b3c..2fc63a8 100644
--- a/tests/tests/location/src/android/location/cts/GnssMeasurementTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssMeasurementTest.java
@@ -19,9 +19,8 @@
 import android.location.GnssMeasurement;
 import android.location.GnssStatus;
 import android.os.Parcel;
-import android.test.AndroidTestCase;
 
-public class GnssMeasurementTest extends AndroidTestCase {
+public class GnssMeasurementTest extends GnssTestCase {
     public void testDescribeContents() {
         GnssMeasurement measurement = new GnssMeasurement();
         measurement.describeContents();
diff --git a/tests/tests/location/src/android/location/cts/GnssMeasurementValuesTest.java b/tests/tests/location/src/android/location/cts/GnssMeasurementValuesTest.java
index e8b8c74..ba6311f 100644
--- a/tests/tests/location/src/android/location/cts/GnssMeasurementValuesTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssMeasurementValuesTest.java
@@ -18,7 +18,6 @@
 
 import android.location.GnssMeasurement;
 import android.location.GnssMeasurementsEvent;
-import android.test.AndroidTestCase;
 import android.util.Log;
 
 import java.util.List;
@@ -39,7 +38,7 @@
  *  5. Verify {@link GnssMeasurement}s (all mandatory fields), the test will fail if any of the
  *     mandatory fields is not populated or in the expected range.
  */
-public class GnssMeasurementValuesTest extends AndroidTestCase {
+public class GnssMeasurementValuesTest extends GnssTestCase {
 
     private static final String TAG = "GnssMeasValuesTest";
     private static final int LOCATION_TO_COLLECT_COUNT = 5;
diff --git a/tests/tests/location/src/android/location/cts/GnssMeasurementWhenNoLocationTest.java b/tests/tests/location/src/android/location/cts/GnssMeasurementWhenNoLocationTest.java
index 7a2bead..6752a34 100644
--- a/tests/tests/location/src/android/location/cts/GnssMeasurementWhenNoLocationTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssMeasurementWhenNoLocationTest.java
@@ -19,7 +19,6 @@
 import android.location.GnssMeasurement;
 import android.location.GnssMeasurementsEvent;
 import android.location.GpsStatus;
-import android.test.AndroidTestCase;
 import android.util.Log;
 
 import java.util.Arrays;
@@ -55,7 +54,7 @@
  5. If {@link GnssMeasurementsEvent}s are received: verify all mandatory fields, the test will fail
     if any of the mandatory fields is not populated or in the expected range.
  */
-public class GnssMeasurementWhenNoLocationTest extends AndroidTestCase {
+public class GnssMeasurementWhenNoLocationTest extends GnssTestCase {
 
     private static final String TAG = "GnssMeasWhenNoFixTest";
     private TestGnssMeasurementListener mMeasurementListener;
@@ -116,7 +115,7 @@
         mTestLocationManager.requestLocationUpdates(mLocationListener);
 
         // Wait for Gps Status updates.
-        assertTrue(mGpsStatusListener.await());
+        mGpsStatusListener.await();
         if (!mMeasurementListener.verifyState()) {
             return;
         }
diff --git a/tests/tests/location/src/android/location/cts/GnssMeasurementsEventCallbackTest.java b/tests/tests/location/src/android/location/cts/GnssMeasurementsEventCallbackTest.java
index 72addce..b670efb 100644
--- a/tests/tests/location/src/android/location/cts/GnssMeasurementsEventCallbackTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssMeasurementsEventCallbackTest.java
@@ -19,9 +19,8 @@
 import android.location.GnssClock;
 import android.location.GnssMeasurement;
 import android.location.GnssMeasurementsEvent;
-import android.test.AndroidTestCase;
 
-public class GnssMeasurementsEventCallbackTest extends AndroidTestCase {
+public class GnssMeasurementsEventCallbackTest extends GnssTestCase {
     private static class MockCallback extends GnssMeasurementsEvent.Callback {
     }
 
@@ -33,6 +32,6 @@
         GnssMeasurementsEvent event = new GnssMeasurementsEvent(
                 clock, new GnssMeasurement[] {m1, m2});
         callback.onGnssMeasurementsReceived(event);
-        callback.onStatusChanged(GnssMeasurementsEvent.STATUS_READY);
+        callback.onStatusChanged(GnssMeasurementsEvent.Callback.STATUS_READY);
     }
 }
diff --git a/tests/tests/location/src/android/location/cts/GnssMeasurementsEventTest.java b/tests/tests/location/src/android/location/cts/GnssMeasurementsEventTest.java
index 51af03d..06f4e5f 100644
--- a/tests/tests/location/src/android/location/cts/GnssMeasurementsEventTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssMeasurementsEventTest.java
@@ -21,12 +21,11 @@
 import android.location.GnssMeasurementsEvent;
 import android.location.GnssStatus;
 import android.os.Parcel;
-import android.test.AndroidTestCase;
 
 import java.util.Collection;
 import java.util.Iterator;
 
-public class GnssMeasurementsEventTest extends AndroidTestCase {
+public class GnssMeasurementsEventTest extends GnssTestCase {
     public void testDescribeContents() {
         GnssClock clock = new GnssClock();
         GnssMeasurement m1 = new GnssMeasurement();
diff --git a/tests/tests/location/src/android/location/cts/GnssNavigationMessageEventCallbackTest.java b/tests/tests/location/src/android/location/cts/GnssNavigationMessageCallbackTest.java
similarity index 69%
rename from tests/tests/location/src/android/location/cts/GnssNavigationMessageEventCallbackTest.java
rename to tests/tests/location/src/android/location/cts/GnssNavigationMessageCallbackTest.java
index 0589c57..842561d 100644
--- a/tests/tests/location/src/android/location/cts/GnssNavigationMessageEventCallbackTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssNavigationMessageCallbackTest.java
@@ -17,18 +17,16 @@
 package android.location.cts;
 
 import android.location.GnssNavigationMessage;
-import android.location.GnssNavigationMessageEvent;
-import android.test.AndroidTestCase;
 
-public class GnssNavigationMessageEventCallbackTest extends AndroidTestCase {
-    private static class MockCallback extends GnssNavigationMessageEvent.Callback {
+public class GnssNavigationMessageCallbackTest extends GnssTestCase {
+    private static class MockCallback extends GnssNavigationMessage.Callback {
     }
 
     public void testAllMethodsExist() {
-        GnssNavigationMessageEvent.Callback callback = new MockCallback();
+        GnssNavigationMessage.Callback callback = new MockCallback();
         GnssNavigationMessage message = new GnssNavigationMessage();
-        GnssNavigationMessageEvent event = new GnssNavigationMessageEvent(message);
+        GnssNavigationMessage event = message;
         callback.onGnssNavigationMessageReceived(event);
-        callback.onStatusChanged(GnssNavigationMessageEvent.STATUS_READY);
+        callback.onStatusChanged(GnssNavigationMessage.Callback.STATUS_READY);
     }
 }
diff --git a/tests/tests/location/src/android/location/cts/GnssNavigationMessageEventTest.java b/tests/tests/location/src/android/location/cts/GnssNavigationMessageEventTest.java
deleted file mode 100644
index 0772092..0000000
--- a/tests/tests/location/src/android/location/cts/GnssNavigationMessageEventTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.location.cts;
-
-import android.location.GnssNavigationMessage;
-import android.location.GnssNavigationMessageEvent;
-import android.os.Parcel;
-import android.test.AndroidTestCase;
-
-public class GnssNavigationMessageEventTest extends AndroidTestCase {
-    public void testDescribeContents() {
-        GnssNavigationMessage message = new GnssNavigationMessage();
-        GnssNavigationMessageEvent event = new GnssNavigationMessageEvent(message);
-        event.describeContents();
-    }
-
-    public void testWriteToParcel() {
-        GnssNavigationMessage message = new GnssNavigationMessage();
-        message.setMessageId(2);
-        GnssNavigationMessageEvent event = new GnssNavigationMessageEvent(message);
-        Parcel parcel = Parcel.obtain();
-        event.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        GnssNavigationMessageEvent newEvent =
-                GnssNavigationMessageEvent.CREATOR.createFromParcel(parcel);
-        assertEquals(2, newEvent.getNavigationMessage().getMessageId());
-    }
-}
diff --git a/tests/tests/location/src/android/location/cts/GnssNavigationMessageRegistrationTest.java b/tests/tests/location/src/android/location/cts/GnssNavigationMessageRegistrationTest.java
index 5348470..f23f885 100644
--- a/tests/tests/location/src/android/location/cts/GnssNavigationMessageRegistrationTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssNavigationMessageRegistrationTest.java
@@ -17,8 +17,6 @@
 package android.location.cts;
 
 import android.location.GnssNavigationMessage;
-import android.location.GnssNavigationMessageEvent;
-import android.test.AndroidTestCase;
 import android.util.Log;
 
 import java.util.List;
@@ -27,28 +25,28 @@
  * Test the {@link GnssNavigationMessage} without location registration.
  *
  * Test steps:
- * 1. Register for {@link GnssNavigationMessageEvent}s.
+ * 1. Register for {@link GnssNavigationMessage}s.
  * 2. Wait for {@link #EVENTS_COUNT} events to arrive.
- * 3. Check {@link GnssNavigationMessageEvent} status: if the status is not
- *    {@link GnssNavigationMessageEvent#STATUS_READY}, the test will be skipped because one of the
+ * 3. Check {@link GnssNavigationMessage} status: if the status is not
+ *    {@link GnssNavigationMessage#Callback#STATUS_READY}, the test will be skipped because one of the
  *    following reasons:
  *          3.1 the device does not support the feature,
  *          3.2 GPS is disabled in the device,
  *          3.3 Location is disabled in the device.
- * 4. If at least one {@link GnssNavigationMessageEvent} is received, the test will pass.
- * 5. If no {@link GnssNavigationMessageEvent}s are received, then check whether the device is
+ * 4. If at least one {@link GnssNavigationMessage} is received, the test will pass.
+ * 5. If no {@link GnssNavigationMessage}s are received, then check whether the device is
  *    deep indoor. This is done by performing the following steps:
  *          2.1 Register for location updates, and {@link GpsStatus} events.
  *          2.2 Wait for {@link TestGpsStatusListener#TIMEOUT_IN_SEC}.
  *          2.3 If no {@link GpsStatus} is received this will mean that the device is located
  *              indoor. Test will be skipped.
- *          2.4 If we receive a {@link GpsStatus}, it mean that {@link GnssNavigationMessageEvent}s
+ *          2.4 If we receive a {@link GpsStatus}, it mean that {@link GnssNavigationMessage}s
  *              are provided only if the application registers for location updates as well:
  *                  2.4.1 The test will pass with a warning for the M release.
  *                  2.4.2 The test might fail in a future Android release, when this requirement
  *                        becomes mandatory.
  */
-public class GnssNavigationMessageRegistrationTest extends AndroidTestCase {
+public class GnssNavigationMessageRegistrationTest extends GnssTestCase {
 
     private static final String TAG = "GpsNavMsgRegTest";
     private TestLocationManager mTestLocationManager;
@@ -81,7 +79,7 @@
     }
 
     /**
-     * Tests that one can listen for {@link GnssNavigationMessageEvent}s for collection purposes.
+     * Tests that one can listen for {@link GnssNavigationMessage}s for collection purposes.
      * It only performs sanity checks for the Navigation messages received.
      */
     public void testGnssNavigationMessageRegistration() throws Exception {
@@ -94,12 +92,12 @@
                 new TestGnssNavigationMessageListener(TAG, EVENTS_COUNT);
         mTestLocationManager.registerGnssNavigationMessageCallback(mTestGnssNavigationMessageListener);
 
-        assertTrue(mTestGnssNavigationMessageListener.await());
+        mTestGnssNavigationMessageListener.await();
         if (!mTestGnssNavigationMessageListener.verifyState()) {
             return;
         }
 
-        List<GnssNavigationMessageEvent> events = mTestGnssNavigationMessageListener.getEvents();
+        List<GnssNavigationMessage> events = mTestGnssNavigationMessageListener.getEvents();
         if (!events.isEmpty()) {
             // Verify mandatory GnssNavigationMessage field values.
             TestMeasurementUtil.verifyGnssNavMessageMandatoryField(events);
@@ -108,7 +106,7 @@
             return;
         }
 
-        // If no {@link GnssNavigationMessageEvent}s are received, then check whether the device is
+        // If no {@link GnssNavigationMessage}s are received, then check whether the device is
         // deep indoor.
         Log.i(TAG, "Did not receive any GPS Navigation Message. Test if device is deep indoor.");
 
@@ -117,8 +115,7 @@
         mTestLocationManager.requestLocationUpdates(mLocationListener);
 
         // Wait for location updates
-        assertTrue(mLocationListener.await());
-
+        mLocationListener.await();
         Log.i(TAG, "Location received = " + mLocationListener.isLocationReceived());
 
         // Register for Gps Status updates
@@ -126,8 +123,7 @@
         mTestLocationManager.addGpsStatusListener(mGpsStatusListener);
 
         // Wait for Gps Status updates
-        assertTrue(mGpsStatusListener.await());
-
+        mGpsStatusListener.await();
         if (!mGpsStatusListener.isGpsStatusReceived()) {
             // Skip the Test. No Satellites are visible. Device may be Indoor
             Log.i(TAG, "No Satellites are visible. Device may be Indoor. Skipping Test.");
diff --git a/tests/tests/location/src/android/location/cts/GnssNavigationMessageTest.java b/tests/tests/location/src/android/location/cts/GnssNavigationMessageTest.java
index 42a67b9..9082dc8 100644
--- a/tests/tests/location/src/android/location/cts/GnssNavigationMessageTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssNavigationMessageTest.java
@@ -17,8 +17,6 @@
 package android.location.cts;
 
 import android.location.GnssNavigationMessage;
-import android.location.GnssNavigationMessageEvent;
-import android.test.AndroidTestCase;
 import android.os.Parcel;
 import android.util.Log;
 
@@ -28,10 +26,10 @@
  * Test the {@link GnssNavigationMessage} values.
  *
  * Test steps:
- * 1. Register for {@link GnssNavigationMessageEvent}s.
+ * 1. Register for {@link GnssNavigationMessage}s.
  * 2. Wait for {@link #EVENTS_COUNT} events to arrive.
- * 3. Check {@link GnssNavigationMessageEvent} status: if the status is not
- *    {@link GnssNavigationMessageEvent#STATUS_READY}, the test will be skipped because one of the
+ * 3. Check {@link GnssNavigationMessage} status: if the status is not
+ *    {@link GnssNavigationMessage.Callback#STATUS_READY}, the test will be skipped because one of the
  *    following reasons:
  *          3.1 the device does not support the feature,
  *          3.2 GPS is disabled in the device,
@@ -39,7 +37,7 @@
  * 4. Verify {@link GnssNavigationMessage}s (all mandatory fields), the test will fail if any of the
  *    mandatory fields is not populated or in the expected range.
  */
-public class GnssNavigationMessageTest extends AndroidTestCase {
+public class GnssNavigationMessageTest extends GnssTestCase {
 
     private static final String TAG = "GpsNavMsgTest";
     private TestLocationManager mTestLocationManager;
@@ -64,7 +62,7 @@
     }
 
     /**
-     * Tests that one can listen for {@link GnssNavigationMessageEvent}s for collection purposes.
+     * Tests that one can listen for {@link GnssNavigationMessage}s for collection purposes.
      * It only performs sanity checks for the Navigation messages received.
      * This tests uses actual data retrieved from GPS HAL.
      */
@@ -78,12 +76,12 @@
                 new TestGnssNavigationMessageListener(TAG, EVENTS_COUNT);
         mTestLocationManager.registerGnssNavigationMessageCallback(mTestGnssNavigationMessageListener);
 
-        assertTrue(mTestGnssNavigationMessageListener.await());
+        mTestGnssNavigationMessageListener.await();
         if (!mTestGnssNavigationMessageListener.verifyState()) {
             return;
         }
 
-        List<GnssNavigationMessageEvent> events = mTestGnssNavigationMessageListener.getEvents();
+        List<GnssNavigationMessage> events = mTestGnssNavigationMessageListener.getEvents();
         assertTrue("No Gps Navigation Message received.", !events.isEmpty());
 
         // Verify mandatory GnssNavigationMessage field values.
diff --git a/tests/tests/location/src/android/location/cts/GnssStatusCallbackTest.java b/tests/tests/location/src/android/location/cts/GnssStatusCallbackTest.java
index d69fc01..b785e1a 100644
--- a/tests/tests/location/src/android/location/cts/GnssStatusCallbackTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssStatusCallbackTest.java
@@ -16,15 +16,14 @@
 
 package android.location.cts;
 
-import android.location.GnssStatusCallback;
-import android.test.AndroidTestCase;
+import android.location.GnssStatus;
 
-public class GnssStatusCallbackTest extends AndroidTestCase {
-    private static class MockCallback extends GnssStatusCallback {
+public class GnssStatusCallbackTest extends GnssTestCase {
+    private static class MockCallback extends GnssStatus.Callback {
     }
 
     public void testAllMethodsExist() {
-        GnssStatusCallback callback = new MockCallback();
+        GnssStatus.Callback callback = new MockCallback();
         callback.onStarted();
         callback.onFirstFix(10);
         callback.onSatelliteStatusChanged(null);
diff --git a/tests/tests/location/src/android/location/cts/GnssTestCase.java b/tests/tests/location/src/android/location/cts/GnssTestCase.java
new file mode 100644
index 0000000..35d8226
--- /dev/null
+++ b/tests/tests/location/src/android/location/cts/GnssTestCase.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.location.cts;
+
+import android.test.AndroidTestCase;
+
+/**
+ * Base Test Case class for all Gnss Tests.
+ */
+public abstract class GnssTestCase extends AndroidTestCase {
+    protected GnssTestCase() {}
+}
\ No newline at end of file
diff --git a/tests/tests/location/src/android/location/cts/LocationManagerTest.java b/tests/tests/location/src/android/location/cts/LocationManagerTest.java
index 36358ab..7fcc2aa 100644
--- a/tests/tests/location/src/android/location/cts/LocationManagerTest.java
+++ b/tests/tests/location/src/android/location/cts/LocationManagerTest.java
@@ -24,9 +24,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.location.Criteria;
-import android.location.GnssNmeaListener;
 import android.location.GnssStatus;
-import android.location.GnssStatusCallback;
 import android.location.GpsStatus;
 import android.location.GpsStatus.Listener;
 import android.location.GpsStatus.NmeaListener;
@@ -34,6 +32,7 @@
 import android.location.LocationListener;
 import android.location.LocationManager;
 import android.location.LocationProvider;
+import android.location.OnNmeaMessageListener;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -920,8 +919,8 @@
         mManager.addNmeaListener(gnssListener, new Handler(handlerThread.getLooper()));
         mManager.removeNmeaListener(gnssListener);
 
-        mManager.addNmeaListener((GnssNmeaListener) null);
-        mManager.removeNmeaListener((GnssNmeaListener) null);
+        mManager.addNmeaListener((OnNmeaMessageListener) null);
+        mManager.removeNmeaListener((OnNmeaMessageListener) null);
     }
 
     public void testIsProviderEnabled() {
@@ -1429,11 +1428,11 @@
         }
     }
 
-    private static class MockGnssNmeaListener implements GnssNmeaListener {
+    private static class MockGnssNmeaListener implements OnNmeaMessageListener {
         private boolean mIsNmeaReceived;
 
         @Override
-        public void onNmeaReceived(long timestamp, String nmea) {
+        public void onNmeaMessage(String name, long timestamp) {
             mIsNmeaReceived = true;
         }
 
@@ -1462,17 +1461,17 @@
         }
     }
 
-    private static class MockGnssStatusCallback extends GnssStatusCallback {
+    private static class MockGnssStatusCallback extends GnssStatus.Callback {
         @Override
         public void onSatelliteStatusChanged(GnssStatus status) {
-            for (int i = 0; i < status.getNumSatellites(); ++i) {
+            for (int i = 0; i < status.getSatelliteCount(); ++i) {
                 status.getAzimuthDegrees(i);
                 status.getCn0DbHz(i);
                 status.getConstellationType(i);
                 status.getElevationDegrees(i);
                 status.getSvid(i);
-                status.hasAlmanac(i);
-                status.hasEphemeris(i);
+                status.hasAlmanacData(i);
+                status.hasEphemerisData(i);
                 status.usedInFix(i);
             }
         }
diff --git a/tests/tests/location/src/android/location/cts/TestGnssMeasurementListener.java b/tests/tests/location/src/android/location/cts/TestGnssMeasurementListener.java
index 86b8495..154cff6 100644
--- a/tests/tests/location/src/android/location/cts/TestGnssMeasurementListener.java
+++ b/tests/tests/location/src/android/location/cts/TestGnssMeasurementListener.java
@@ -62,7 +62,7 @@
     @Override
     public void onStatusChanged(int status) {
         mStatus = status;
-        if (mStatus != GnssMeasurementsEvent.STATUS_READY) {
+        if (mStatus != GnssMeasurementsEvent.Callback.STATUS_READY) {
             mCountDownLatch.countDown();
         }
     }
@@ -77,13 +77,13 @@
      */
     public boolean verifyState() {
         switch (getStatus()) {
-            case GnssMeasurementsEvent.STATUS_NOT_SUPPORTED:
+            case GnssMeasurementsEvent.Callback.STATUS_NOT_SUPPORTED:
                 SoftAssert.failAsWarning(mTag, "GnssMeasurements is not supported in the device:"
                         + " verifications performed by this test will be skipped.");
                 return false;
-            case GnssMeasurementsEvent.STATUS_READY:
+            case GnssMeasurementsEvent.Callback.STATUS_READY:
                 return true;
-            case GnssMeasurementsEvent.STATUS_GNSS_LOCATION_DISABLED:
+            case GnssMeasurementsEvent.Callback.STATUS_LOCATION_DISABLED:
                 Log.i(mTag, "Location or GPS is disabled on the device: skipping the test.");
                 return false;
             default:
diff --git a/tests/tests/location/src/android/location/cts/TestGnssNavigationMessageListener.java b/tests/tests/location/src/android/location/cts/TestGnssNavigationMessageListener.java
index 7136fb1..3765f3c 100644
--- a/tests/tests/location/src/android/location/cts/TestGnssNavigationMessageListener.java
+++ b/tests/tests/location/src/android/location/cts/TestGnssNavigationMessageListener.java
@@ -18,7 +18,7 @@
 
 import junit.framework.Assert;
 
-import android.location.GnssNavigationMessageEvent;
+import android.location.GnssNavigationMessage;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -29,7 +29,7 @@
 /**
  * Used for receiving GPS satellite Navigation Messages from the GPS engine.
  */
-class TestGnssNavigationMessageListener extends GnssNavigationMessageEvent.Callback {
+class TestGnssNavigationMessageListener extends GnssNavigationMessage.Callback {
 
     // Timeout in sec for count down latch wait
     private static final long TIMEOUT_IN_SEC = 90L;
@@ -38,7 +38,7 @@
 
     private final String mTag;
     private final int mEventsToCollect;
-    private final List<GnssNavigationMessageEvent> mEvents;
+    private final List<GnssNavigationMessage> mEvents;
     private final CountDownLatch mCountDownLatch;
 
     TestGnssNavigationMessageListener(String tag, int eventsToCollect) {
@@ -49,7 +49,7 @@
     }
 
     @Override
-    public void onGnssNavigationMessageReceived(GnssNavigationMessageEvent event) {
+    public void onGnssNavigationMessageReceived(GnssNavigationMessage event) {
         mEvents.add(event);
         if (mEvents.size() > mEventsToCollect) {
             mCountDownLatch.countDown();
@@ -59,7 +59,7 @@
     @Override
     public void onStatusChanged(int status) {
         mStatus = status;
-        if (mStatus != GnssNavigationMessageEvent.STATUS_READY) {
+        if (mStatus != GnssNavigationMessage.Callback.STATUS_READY) {
             mCountDownLatch.countDown();
         }
     }
@@ -84,17 +84,17 @@
      */
     public boolean verifyState() {
         switch (getStatus()) {
-            case GnssNavigationMessageEvent.STATUS_NOT_SUPPORTED:
+            case GnssNavigationMessage.Callback.STATUS_NOT_SUPPORTED:
                 SoftAssert.failAsWarning(mTag, "GnssNavigationMessage is not supported in the"
                         + " device: verifications performed by this test will be skipped.");
                 return false;
-            case GnssNavigationMessageEvent.STATUS_READY:
+            case GnssNavigationMessage.Callback.STATUS_READY:
                 return true;
-            case GnssNavigationMessageEvent.STATUS_GNSS_LOCATION_DISABLED:
+            case GnssNavigationMessage.Callback.STATUS_LOCATION_DISABLED:
                 Log.i(mTag, "Location or GPS is disabled on the device: skipping the test.");
                 return false;
             default:
-                Assert.fail("GnssNavigationMessageEvent status callback was not received.");
+                Assert.fail("GnssNavigationMessage status callback was not received.");
         }
         return false;
     }
@@ -104,7 +104,7 @@
      *
      * @return mEvents list of GPS Navigation Message Events
      */
-    public List<GnssNavigationMessageEvent> getEvents() {
+    public List<GnssNavigationMessage> getEvents() {
         return mEvents;
     }
 }
diff --git a/tests/tests/location/src/android/location/cts/TestGnssStatusCallback.java b/tests/tests/location/src/android/location/cts/TestGnssStatusCallback.java
index c1486e7..b5e102e 100644
--- a/tests/tests/location/src/android/location/cts/TestGnssStatusCallback.java
+++ b/tests/tests/location/src/android/location/cts/TestGnssStatusCallback.java
@@ -17,7 +17,6 @@
 package android.location.cts;
 
 import android.location.GnssStatus;
-import android.location.GnssStatusCallback;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -27,7 +26,7 @@
 /**
  * Used for receiving notifications when GNSS status has changed.
  */
-class TestGnssStatusCallback extends GnssStatusCallback {
+class TestGnssStatusCallback extends GnssStatus.Callback {
 
     private volatile boolean mGpsStatusReceived;
     private GnssStatus mGnssStatus = null;
diff --git a/tests/tests/location/src/android/location/cts/TestLocationManager.java b/tests/tests/location/src/android/location/cts/TestLocationManager.java
index 3ab48dd..28068a0 100644
--- a/tests/tests/location/src/android/location/cts/TestLocationManager.java
+++ b/tests/tests/location/src/android/location/cts/TestLocationManager.java
@@ -18,7 +18,7 @@
 
 import android.content.Context;
 import android.location.GnssMeasurementsEvent;
-import android.location.GnssNavigationMessageEvent;
+import android.location.GnssNavigationMessage;
 import android.location.GpsStatus;
 import android.location.LocationListener;
 import android.location.LocationManager;
@@ -158,11 +158,11 @@
     /**
      * Add a GNSS Navigation Message callback.
      *
-     * @param callback a {@link GnssNavigationMessageEvent.Callback} object to register.
+     * @param callback a {@link GnssNavigationMessage.Callback} object to register.
      * @return {@code true} if the listener was added successfully, {@code false} otherwise.
      */
     public boolean registerGnssNavigationMessageCallback(
-            GnssNavigationMessageEvent.Callback callback) {
+            GnssNavigationMessage.Callback callback) {
         Log.i(TAG, "Add Gnss Navigation Message Callback.");
         return mLocationManager.registerGnssNavigationMessageCallback(callback);
     }
@@ -170,12 +170,12 @@
     /**
      * Add a GNSS Navigation Message callback.
      *
-     * @param callback a {@link GnssNavigationMessageEvent.Callback} object to register.
+     * @param callback a {@link GnssNavigationMessage.Callback} object to register.
      * @param handler the handler that the callback runs at.
      * @return {@code true} if the listener was added successfully, {@code false} otherwise.
      */
     public boolean registerGnssNavigationMessageCallback(
-            GnssNavigationMessageEvent.Callback callback, Handler handler) {
+            GnssNavigationMessage.Callback callback, Handler handler) {
         Log.i(TAG, "Add Gnss Navigation Message Callback.");
         return mLocationManager.registerGnssNavigationMessageCallback(callback, handler);
     }
@@ -183,9 +183,9 @@
     /**
      * Removes a GNSS Navigation Message callback.
      *
-     * @param callback a {@link GnssNavigationMessageEvent.Callback} object to remove.
+     * @param callback a {@link GnssNavigationMessage.Callback} object to remove.
      */
-    public void unregisterGnssNavigationMessageCallback(GnssNavigationMessageEvent.Callback callback) {
+    public void unregisterGnssNavigationMessageCallback(GnssNavigationMessage.Callback callback) {
         Log.i(TAG, "Remove Gnss Navigation Message Callback.");
         mLocationManager.unregisterGnssNavigationMessageCallback(callback);
     }
diff --git a/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java b/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
index f7cf144..f812f62 100644
--- a/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
+++ b/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
@@ -18,7 +18,6 @@
 
 import android.location.GnssMeasurement;
 import android.location.GnssNavigationMessage;
-import android.location.GnssNavigationMessageEvent;
 import android.location.GnssStatus;
 import android.location.LocationManager;
 import android.os.Build;
@@ -581,11 +580,10 @@
      *
      * @param events GnssNavigationMessageEvents
      */
-    public static void verifyGnssNavMessageMandatoryField(List<GnssNavigationMessageEvent> events) {
+    public static void verifyGnssNavMessageMandatoryField(List<GnssNavigationMessage> events) {
         // Verify mandatory GnssNavigationMessage field values.
         SoftAssert softAssert = new SoftAssert(TAG);
-        for (GnssNavigationMessageEvent event : events) {
-            GnssNavigationMessage message = event.getNavigationMessage();
+        for (GnssNavigationMessage message : events) {
             int type = message.getType();
             softAssert.assertTrue("Gnss Navigation Message Type:expected [0x0101 - 0x0104]," +
                             " actual = " + type,
diff --git a/tests/tests/location/src/android/location/cts/TestUtils.java b/tests/tests/location/src/android/location/cts/TestUtils.java
index 61f63d9..82d644e 100644
--- a/tests/tests/location/src/android/location/cts/TestUtils.java
+++ b/tests/tests/location/src/android/location/cts/TestUtils.java
@@ -22,7 +22,7 @@
 public class TestUtils {
     private static final long STANDARD_WAIT_TIME_MS = 50;
     private static final long STANDARD_SLEEP_TIME_MS = 50;
-    private static final long STANDARD_WAIT_TIME_ROUNDS = 3000;
+    private static final long STANDARD_WAIT_TIME_ROUNDS = 1200;
 
     public static boolean waitFor(CountDownLatch latch) throws InterruptedException {
         // Since late 2014, if the main thread has been occupied for long enough, Android will
diff --git a/tests/tests/media/AndroidManifest.xml b/tests/tests/media/AndroidManifest.xml
index 5e97cc2..9064ade 100644
--- a/tests/tests/media/AndroidManifest.xml
+++ b/tests/tests/media/AndroidManifest.xml
@@ -36,6 +36,13 @@
             android:label="AudioManagerStub"/>
         <activity android:name="android.media.cts.AudioManagerStubHelper"
             android:label="AudioManagerStubHelper"/>
+        <activity android:name="android.media.cts.DecodeAccuracyTestActivity"
+            android:label="DecodeAccuracyTestActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
         <activity android:name="android.media.cts.MediaStubActivity"
             android:label="MediaStubActivity"
             android:screenOrientation="nosensor"
diff --git a/tests/tests/media/assets/360pvp9decodertest.webm b/tests/tests/media/assets/360pvp9decodertest.webm
new file mode 100644
index 0000000..e35e7a8
--- /dev/null
+++ b/tests/tests/media/assets/360pvp9decodertest.webm
Binary files differ
diff --git a/tests/tests/media/assets/480ph264decodertest.mp4 b/tests/tests/media/assets/480ph264decodertest.mp4
new file mode 100644
index 0000000..9b7e894
--- /dev/null
+++ b/tests/tests/media/assets/480ph264decodertest.mp4
Binary files differ
diff --git a/tests/tests/media/res/layout/test_runner_activity.xml b/tests/tests/media/res/layout/test_runner_activity.xml
new file mode 100644
index 0000000..8cc88ea
--- /dev/null
+++ b/tests/tests/media/res/layout/test_runner_activity.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical">
+        <HorizontalScrollView
+            android:layout_width="fill_parent"
+            android:layout_height="250dp">
+                <ScrollView
+                    android:layout_width="wrap_content"
+                    android:layout_height="fill_parent">
+                        <RelativeLayout
+                            android:id="@+id/attach_view"
+                            android:layout_width="fill_parent"
+                            android:layout_height="wrap_content"
+                            android:layout_gravity="start"/>
+                </ScrollView>
+        </HorizontalScrollView>
+        <ListView
+            android:id="@+id/test_case_list"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"/>
+</LinearLayout>
diff --git a/tests/tests/media/res/raw/h264decodertestgolden.png b/tests/tests/media/res/raw/h264decodertestgolden.png
new file mode 100644
index 0000000..bfaea26
--- /dev/null
+++ b/tests/tests/media/res/raw/h264decodertestgolden.png
Binary files differ
diff --git a/tests/tests/media/res/raw/sinesweepopus.mkv b/tests/tests/media/res/raw/sinesweepopus.mkv
new file mode 100644
index 0000000..230dd36
--- /dev/null
+++ b/tests/tests/media/res/raw/sinesweepopus.mkv
Binary files differ
diff --git a/tests/tests/media/res/raw/sinesweepvorbis.mkv b/tests/tests/media/res/raw/sinesweepvorbis.mkv
new file mode 100644
index 0000000..613ab71
--- /dev/null
+++ b/tests/tests/media/res/raw/sinesweepvorbis.mkv
Binary files differ
diff --git a/tests/tests/media/res/raw/tones.wav b/tests/tests/media/res/raw/tones.wav
new file mode 100644
index 0000000..ec54c96
--- /dev/null
+++ b/tests/tests/media/res/raw/tones.wav
Binary files differ
diff --git a/tests/tests/media/res/raw/vp9decodertestgolden.png b/tests/tests/media/res/raw/vp9decodertestgolden.png
new file mode 100644
index 0000000..cad6778
--- /dev/null
+++ b/tests/tests/media/res/raw/vp9decodertestgolden.png
Binary files differ
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerTest.java b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
index c78f82a..d7ec5f1 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
@@ -81,8 +81,15 @@
     }
 
     public void testSoundEffects() throws Exception {
-        // set relative setting
-        mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+        try {
+            Utils.toggleNotificationPolicyAccess(
+                    mContext.getPackageName(), getInstrumentation(), true);
+            // set relative setting
+            mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+        } finally {
+            Utils.toggleNotificationPolicyAccess(
+                mContext.getPackageName(), getInstrumentation(), false);
+        }
         Settings.System.putInt(mContext.getContentResolver(), SOUND_EFFECTS_ENABLED, 1);
 
         // should hear sound after loadSoundEffects() called.
@@ -343,6 +350,9 @@
     }
 
     public void testSetRingerModePolicyAccess() throws Exception {
+        if (mUseFixedVolume || mIsTelevision) {
+            return;
+        }
         try {
             // Apps without policy access cannot change silent -> normal or silent -> vibrate.
             Utils.toggleNotificationPolicyAccess(
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java b/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java
index e8239ff..a8fb8fc 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java
@@ -162,7 +162,7 @@
         // just call the callback once directly so it's marked as tested
         final AudioManager.AudioRecordingCallback arc =
                 (AudioManager.AudioRecordingCallback) callback;
-        arc.onRecordConfigChanged(new AudioRecordingConfiguration[0]);
+        arc.onRecordingConfigChanged(new AudioRecordingConfiguration[0]);
     }
 
     public void testParcel() throws Exception {
@@ -216,7 +216,7 @@
         }
 
         @Override
-        public void onRecordConfigChanged(AudioRecordingConfiguration[] configs) {
+        public void onRecordingConfigChanged(AudioRecordingConfiguration[] configs) {
             mCalled = true;
             mParamMatch = verifyAudioConfig(mTestSource, mTestSession, mAudioRecord.getFormat(),
                     mAudioRecord.getRoutedDevice(), configs);
diff --git a/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java b/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java
index e1e5c93..9ad8de9 100644
--- a/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java
+++ b/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java
@@ -367,7 +367,6 @@
         mMediaCodecPlayer = new MediaCodecClearKeyPlayer(
                 getActivity().getSurfaceHolder(),
                 mSessionId,
-                initDataType,
                 mContext.getResources());
 
         mMediaCodecPlayer.setAudioDataSource(audioUrl, null, audioEncrypted);
diff --git a/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java b/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java
new file mode 100644
index 0000000..319df5a
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.cts;
+
+import android.media.cts.R;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.cts.util.MediaUtils;
+import android.graphics.Bitmap;
+import android.os.Build;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.cts.util.TimeoutReq;
+
+@TargetApi(16)
+public class DecodeAccuracyTest extends DecodeAccuracyTestBase {
+
+    private static final String TAG = DecodeAccuracyTest.class.getSimpleName();
+    private static final String H264_VIDEO_FILE_NAME = "480ph264decodertest.mp4";
+    private static final String VP9_VIDEO_FILE_NAME = "360pvp9decodertest.webm";
+    private static final int ALLOWED_GREATEST_PIXEL_DIFFERENCE = 90;
+    private static final int TESTCASE_WAITTIME_MIN = 1;
+    private static final int OFFSET = 10;
+
+    /* <------------- Tests Using H264 -------------> */
+    @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+    public void testH264TextureViewVideoDecode() throws Exception {
+        runDecodeAccuracyTest(
+                new TextureViewFactory(),
+                new VideoFormat(H264_VIDEO_FILE_NAME));
+    }
+
+    @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+    public void testH264TextureViewLargerHeightVideoDecode() throws Exception {
+        runDecodeAccuracyTest(
+                new TextureViewFactory(),
+                getLargerHeightVideoFormat(new VideoFormat(H264_VIDEO_FILE_NAME)));
+    }
+
+    @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+    public void testH264TextureViewLargerWidthVideoDecode() throws Exception {
+        runDecodeAccuracyTest(
+                new TextureViewFactory(),
+                getLargerWidthVideoFormat(new VideoFormat(H264_VIDEO_FILE_NAME)));
+    }
+
+    @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+    public void testH264GLViewVideoDecode() throws Exception {
+        runDecodeAccuracyTest(
+                new GLSurfaceViewFactory(),
+                new VideoFormat(H264_VIDEO_FILE_NAME));
+    }
+
+    @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+    public void testH264GLViewLargerHeightVideoDecode() throws Exception {
+        runDecodeAccuracyTest(
+                new GLSurfaceViewFactory(),
+                getLargerHeightVideoFormat(new VideoFormat(H264_VIDEO_FILE_NAME)));
+    }
+
+    @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+    public void testH264GLViewLargerWidthVideoDecode() throws Exception {
+        runDecodeAccuracyTest(
+                new GLSurfaceViewFactory(),
+                getLargerWidthVideoFormat(new VideoFormat(H264_VIDEO_FILE_NAME)));
+    }
+
+    /* <------------- Tests Using VP9 -------------> */
+    @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+    public void testVP9TextureViewVideoDecode() throws Exception {
+        runDecodeAccuracyTest(
+                new TextureViewFactory(),
+                new VideoFormat(VP9_VIDEO_FILE_NAME));
+    }
+
+    @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+    public void testVP9TextureViewLargerHeightVideoDecode() throws Exception {
+        runDecodeAccuracyTest(
+                new TextureViewFactory(),
+                getLargerHeightVideoFormat(new VideoFormat(VP9_VIDEO_FILE_NAME)));
+    }
+
+    @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+    public void testVP9TextureViewLargerWidthVideoDecode() throws Exception {
+        runDecodeAccuracyTest(
+                new TextureViewFactory(),
+                getLargerWidthVideoFormat(new VideoFormat(VP9_VIDEO_FILE_NAME)));
+    }
+
+    @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+    public void testVP9GLViewVideoDecode() throws Exception {
+        runDecodeAccuracyTest(
+                new GLSurfaceViewFactory(),
+                new VideoFormat(VP9_VIDEO_FILE_NAME));
+    }
+
+    @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+    public void testVP9GLViewLargerHeightVideoDecode() throws Exception {
+        runDecodeAccuracyTest(
+                new GLSurfaceViewFactory(),
+                getLargerHeightVideoFormat(new VideoFormat(VP9_VIDEO_FILE_NAME)));
+    }
+
+    @TimeoutReq(minutes = TESTCASE_WAITTIME_MIN)
+    public void testVP9GLViewLargerWidthVideoDecode() throws Exception {
+        runDecodeAccuracyTest(
+                new GLSurfaceViewFactory(),
+                getLargerWidthVideoFormat(new VideoFormat(VP9_VIDEO_FILE_NAME)));
+    }
+
+    private void runDecodeAccuracyTest(VideoViewFactory videoViewFactory, VideoFormat videoFormat) {
+        checkNotNull(videoViewFactory);
+        checkNotNull(videoFormat);
+        if (!DisplayUtil.canPlay360p(getHelper().getContext())) {
+            MediaUtils.skipTest("Display does not support 360p.");
+            return;
+        }
+        if (!DisplayUtil.currentOrientationCanPlay360p(getHelper().getContext())) {
+            Log.w(TAG, "Current screen orientation does not support 360p.");
+            Log.i(TAG, "Rotate screen orientation and continue.");
+            getHelper().rotateOrientation();
+        }
+        View videoView = videoViewFactory.createView(getHelper().getContext());
+        // If view is intended and available to display.
+        if (videoView != null) {
+            getHelper().generateView(videoView);
+        }
+        videoViewFactory.waitForViewIsAvailable();
+
+        decodeVideo(videoFormat, videoViewFactory);
+        validateResult(videoFormat, videoViewFactory);
+
+        if (videoView != null) {
+            getHelper().cleanUpView(videoView);
+        }
+        videoViewFactory.release();
+        getHelper().unsetOrientation();
+    }
+
+    private void decodeVideo(VideoFormat videoFormat, VideoViewFactory videoViewFactory) {
+        final SimplePlayer player = new SimplePlayer(getHelper().getContext());
+        final SimplePlayer.PlayerResult playerResult = player.decodeVideoFrames(
+                videoViewFactory.getSurface(), videoFormat, 10);
+        assertTrue("Failed to configure video decoder.", playerResult.isConfigureSuccess());
+        assertTrue("Failed to start video decoder.", playerResult.isStartSuccess());
+        assertTrue("Failed to decode the video.", playerResult.isSuccess());
+    }
+
+    private void validateResult(VideoFormat videoFormat, VideoViewFactory videoViewFactory) {
+        final Bitmap result = getHelper().generateBitmapFromVideoViewSnapshot(
+                videoViewFactory.getVideoViewSnapshot());
+        final Bitmap golden;
+        final String mime = videoFormat.getMimeType();
+        if (mime.equals(MimeTypes.VIDEO_H264)) {
+            golden = getHelper().generateBitmapFromImageResourceId(R.raw.h264decodertestgolden);
+        } else if (mime.equals(MimeTypes.VIDEO_VP9)) {
+            golden = getHelper().generateBitmapFromImageResourceId(R.raw.vp9decodertestgolden);
+        } else {
+            fail("Unsupported MIME type " + mime);
+            return;
+        }
+        final BitmapCompare.Difference difference = BitmapCompare.computeDifference(golden, result);
+        assertTrue("Greatest pixel difference is "
+                    + difference.greatestPixelDifference
+                    + (difference.greatestPixelDifferenceCoordinates != null
+                    ? " at (" + difference.greatestPixelDifferenceCoordinates.first + ", "
+                    + difference.greatestPixelDifferenceCoordinates.second + ")" : "")
+                    + " which is over the allowed difference " + ALLOWED_GREATEST_PIXEL_DIFFERENCE,
+                    difference.greatestPixelDifference <= ALLOWED_GREATEST_PIXEL_DIFFERENCE);
+    }
+
+    private static VideoFormat getLargerHeightVideoFormat(VideoFormat videoFormat) {
+        return new VideoFormat(videoFormat) {
+            @Override
+            public int getHeight() {
+                return super.getHeight() + OFFSET;
+            }
+            @Override
+            public int getMaxHeight() {
+                return super.getHeight() * 2 + OFFSET;
+            }
+            @Override
+            public int getMaxWidth() {
+                return super.getWidth() * 2 + OFFSET;
+            }
+        };
+    }
+
+    private static VideoFormat getLargerWidthVideoFormat(VideoFormat videoFormat) {
+        return new VideoFormat(videoFormat) {
+            @Override
+            public int getWidth() {
+                return super.getWidth() + OFFSET;
+            }
+            @Override
+            public int getMaxHeight() {
+                return super.getHeight() * 2 + OFFSET;
+            }
+            @Override
+            public int getMaxWidth() {
+                return super.getWidth() * 2 + OFFSET;
+            }
+        };
+    }
+
+    private static final class DisplayUtil {
+
+        public static boolean canPlay360p(Context context) {
+            return displayMetricsHasMinPixelSize(context, 360);
+        }
+
+        public static boolean currentOrientationCanPlay360p(Context context) {
+            DisplayMetrics metrics = getDisplayMetrics(context);
+            return metrics.widthPixels >= 480 && metrics.heightPixels >= 360;
+        }
+
+        private static boolean displayMetricsHasMinPixelSize(Context context, int minPixelSize) {
+            return getDisplayMetricsMinPixelSize(context) >= minPixelSize;
+        }
+
+        private static int getDisplayMetricsMinPixelSize(Context context) {
+            DisplayMetrics metrics = getDisplayMetrics(context);
+            return Math.min(metrics.widthPixels, metrics.heightPixels);
+        }
+
+        private static DisplayMetrics getDisplayMetrics(Context context) {
+            checkNotNull(context);
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+                DisplayMetrics metrics = new DisplayMetrics();
+                ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
+                        .getDefaultDisplay().getRealMetrics(metrics);
+                return metrics;
+            } else {
+                return context.getResources().getDisplayMetrics();
+            }
+        }
+
+    }
+
+}
diff --git a/tests/tests/media/src/android/media/cts/DecodeAccuracyTestActivity.java b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestActivity.java
new file mode 100644
index 0000000..da06844
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.cts;
+
+import android.media.cts.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public class DecodeAccuracyTestActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.test_runner_activity);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+    }
+
+}
diff --git a/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
new file mode 100644
index 0000000..8caf495
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
@@ -0,0 +1,1379 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.cts;
+
+import android.media.cts.R;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.graphics.SurfaceTexture;
+import android.media.MediaCodec;
+import android.media.MediaCodec.BufferInfo;
+import android.media.MediaCodec.CodecException;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+import android.net.Uri;
+import android.opengl.EGL14;
+import android.opengl.GLES11Ext;
+import android.opengl.GLES20;
+import android.opengl.GLSurfaceView;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+import android.util.Pair;
+import android.util.SparseArray;
+import android.view.Surface;
+import android.view.TextureView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.RelativeLayout;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.util.concurrent.TimeUnit;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+
+@TargetApi(16)
+public class DecodeAccuracyTestBase
+    extends ActivityInstrumentationTestCase2<DecodeAccuracyTestActivity> {
+
+    protected Context mContext;
+    protected Resources mResources;
+    protected DecodeAccuracyTestActivity mActivity;
+    protected TestHelper testHelper;
+
+    public DecodeAccuracyTestBase() {
+        super(DecodeAccuracyTestActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+        getInstrumentation().waitForIdleSync();
+        mContext = getInstrumentation().getTargetContext();
+        mResources = mContext.getResources();
+        testHelper = new TestHelper(mContext, mActivity);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mActivity = null;
+        super.tearDown();
+    }
+
+    protected TestHelper getHelper() {
+        return testHelper;
+    }
+
+    public static <T> T checkNotNull(T reference) {
+        assertNotNull(reference);
+        return reference;
+    }
+
+    public static class SimplePlayer {
+
+        public static final long DECODE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(1) / 2;
+
+        private static final int NO_TRACK_INDEX = -3;
+        private static final long DEQUEUE_TIMEOUT_US = 20;
+        private static final String TAG = SimplePlayer.class.getSimpleName();
+
+        private final Context context;
+        private final MediaExtractor extractor;
+        private MediaCodec decoder;
+
+        public SimplePlayer(Context context) {
+            this(context, new MediaExtractor());
+        }
+
+        public SimplePlayer(Context context, MediaExtractor extractor) {
+            this.context = checkNotNull(context);
+            this.extractor = checkNotNull(extractor);
+        }
+
+        /*
+         * The function play the corresponding file for certain number of frames,
+         *
+         * @param surface is the surface view of decoder output.
+         * @param videoFormat is the format of the video to extract and decode.
+         * @param numOfTotalFrame is the number of Frame wish to play.
+         * @return a PlayerResult object indicating success or failure.
+         */
+        public PlayerResult decodeVideoFrames(
+                Surface surface, VideoFormat videoFormat, int numOfTotalFrames) {
+            PlayerResult playerResult;
+            if (prepare(surface, videoFormat)) {
+                if (startDecoder()) {
+                    playerResult = decodeFramesAndDisplay(
+                            surface, numOfTotalFrames, numOfTotalFrames * DECODE_TIMEOUT_MS);
+                } else {
+                    playerResult = PlayerResult.failToStart();
+                }
+            } else {
+                playerResult = new PlayerResult();
+            }
+            release();
+            return new PlayerResult(playerResult);
+        }
+
+        public PlayerResult decodeVideoFrames(VideoFormat videoFormat, int numOfTotalFrames) {
+            return decodeVideoFrames(null, videoFormat, numOfTotalFrames);
+        }
+
+        /*
+         * The function set up the extractor and decoder with proper format.
+         * This must be called before decodeFramesAndDisplay.
+         */
+        private boolean prepare(Surface surface, VideoFormat videoFormat) {
+            if (!setExtractorDataSource(videoFormat)) {
+                return false;
+            }
+            int trackNum = getFirstVideoTrackIndex(extractor);
+            if (trackNum == NO_TRACK_INDEX) {
+                return false;
+            }
+            extractor.selectTrack(trackNum);
+            MediaFormat mediaFormat = extractor.getTrackFormat(trackNum);
+            configureFormat(mediaFormat, videoFormat);
+            return configureDecoder(surface, mediaFormat);
+        }
+
+        /* The function decode video frames and display in a surface. */
+        private PlayerResult decodeFramesAndDisplay(
+                Surface surface, int numOfTotalFrames, long timeOutMs) {
+            checkNotNull(decoder);
+            int numOfDecodedFrames = 0;
+            long decodeStart = 0;
+            boolean renderToSurface = surface != null ? true : false;
+            BufferInfo info = new BufferInfo();
+            ByteBuffer inputBuffer;
+            ByteBuffer[] inputBufferArray = decoder.getInputBuffers();
+            long loopStart = SystemClock.elapsedRealtime();
+
+            while (numOfDecodedFrames < numOfTotalFrames
+                    && (SystemClock.elapsedRealtime() - loopStart < timeOutMs)) {
+                try {
+                    int inputBufferIndex = decoder.dequeueInputBuffer(DEQUEUE_TIMEOUT_US);
+                    if (inputBufferIndex >= 0) {
+                        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+                            inputBuffer = inputBufferArray[inputBufferIndex];
+                        } else {
+                            inputBuffer = decoder.getInputBuffer(inputBufferIndex);
+                        }
+                        if (decodeStart == 0) {
+                            decodeStart = SystemClock.elapsedRealtime();
+                        }
+                        int sampleSize = extractor.readSampleData(inputBuffer, 0);
+                        if (sampleSize > 0) {
+                            decoder.queueInputBuffer(
+                                    inputBufferIndex, 0, sampleSize, extractor.getSampleTime(), 0);
+                            extractor.advance();
+                        }
+                    }
+                    int decoderStatus = decoder.dequeueOutputBuffer(info, DEQUEUE_TIMEOUT_US);
+                    if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+                        break;
+                    }
+                    if (decoderStatus >= 0 && info.size > 0) {
+                        decoder.releaseOutputBuffer(decoderStatus, renderToSurface);
+                        numOfDecodedFrames++;
+                    }
+                } catch (IllegalStateException exception) {
+                    Log.e(TAG, "IllegalStateException in decodeFramesAndDisplay " + exception);
+                    break;
+                }
+            }
+            long totalTime = SystemClock.elapsedRealtime() - decodeStart;
+            return new PlayerResult(true, true, numOfTotalFrames == numOfDecodedFrames, totalTime);
+        }
+
+        private void release() {
+            decoderRelease();
+            extractorRelease();
+        }
+
+        private boolean setExtractorDataSource(VideoFormat videoFormat) {
+            try {
+                extractor.setDataSource(context, videoFormat.loadUri(context), null);
+            } catch (IOException exception) {
+                Log.e(TAG, "IOException in setDataSource", exception);
+                return false;
+            }
+            return true;
+        }
+
+        private boolean configureDecoder(Surface surface, MediaFormat mediaFormat) {
+            try {
+                decoder = MediaCodec.createDecoderByType(
+                        mediaFormat.getString(MediaFormat.KEY_MIME));
+                decoder.configure(mediaFormat, surface, null, 0);
+            } catch (Exception exception) {
+                if (exception instanceof IOException) {
+                    Log.e(TAG, "IOException in createDecoderByType", exception);
+                } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
+                        && exception instanceof CodecException) {
+                    Log.e(TAG, "CodecException in createDecoderByType", exception);
+                    decoder.reset();
+                } else {
+                    Log.e(TAG, "Unknown exception in createDecoderByType", exception);
+                }
+                decoderRelease();
+                return false;
+            }
+            return true;
+        }
+
+        private boolean startDecoder() {
+            try {
+                decoder.start();
+            } catch (Exception exception) {
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
+                        && exception instanceof CodecException) {
+                    Log.e(TAG, "CodecException in startDecoder", exception);
+                    decoder.reset();
+                } else if (exception instanceof IllegalStateException) {
+                    Log.e(TAG, "IllegalStateException in startDecoder", exception);
+                } else {
+                    Log.e(TAG, "Unknown exception in startDecoder", exception);
+                }
+                decoderRelease();
+                return false;
+            }
+            return true;
+        }
+
+        private void decoderRelease() {
+            if (decoder == null) {
+                return;
+            }
+            try {
+                decoder.stop();
+            } catch (IllegalStateException exception) {
+                // IllegalStateException happens when decoder fail to start.
+                Log.e(TAG, "IllegalStateException in decoder stop" + exception);
+            } finally {
+                try {
+                    decoder.release();
+                } catch (IllegalStateException exception) {
+                    Log.e(TAG, "IllegalStateException in decoder release" + exception);
+                }
+            }
+            decoder = null;
+        }
+
+        private void extractorRelease() {
+            if (extractor == null) {
+                return;
+            }
+            try {
+                extractor.release();
+            } catch (IllegalStateException exception) {
+                Log.e(TAG, "IllegalStateException in extractor release" + exception);
+            }
+        }
+
+        private static void configureFormat(MediaFormat mediaFormat, VideoFormat videoFormat) {
+            checkNotNull(mediaFormat);
+            checkNotNull(videoFormat);
+            videoFormat.setMimeType(mediaFormat.getString(MediaFormat.KEY_MIME));
+            videoFormat.setWidth(mediaFormat.getInteger(MediaFormat.KEY_WIDTH));
+            videoFormat.setHeight(mediaFormat.getInteger(MediaFormat.KEY_HEIGHT));
+            mediaFormat.setInteger(MediaFormat.KEY_WIDTH, videoFormat.getWidth());
+            mediaFormat.setInteger(MediaFormat.KEY_HEIGHT, videoFormat.getHeight());
+
+            if (videoFormat.getMaxWidth() != VideoFormat.UNSET
+                    && videoFormat.getMaxHeight() != VideoFormat.UNSET) {
+                mediaFormat.setInteger(MediaFormat.KEY_MAX_WIDTH, videoFormat.getMaxWidth());
+                mediaFormat.setInteger(MediaFormat.KEY_MAX_HEIGHT, videoFormat.getMaxHeight());
+            }
+        }
+
+        /*
+         * The function returns the first video track found.
+         *
+         * @param extractor is the media extractor instantiated with a video uri.
+         * @return the index of the first video track if found, NO_TRACK_INDEX otherwise.
+         */
+        private static int getFirstVideoTrackIndex(MediaExtractor extractor) {
+            for (int i = 0; i < extractor.getTrackCount(); i++) {
+                MediaFormat trackMediaFormat = extractor.getTrackFormat(i);
+                if (trackMediaFormat.getString(MediaFormat.KEY_MIME).startsWith("video/")) {
+                    return i;
+                }
+            }
+            Log.e(TAG, "couldn't get a video track");
+            return NO_TRACK_INDEX;
+        }
+
+        /* Stores the result from SimplePlayer. */
+        public static final class PlayerResult {
+
+            public static final int UNSET = -1;
+            private final boolean configureSuccess;
+            private final boolean startSuccess;
+            private final boolean decodeSuccess;
+            private final long totalTime;
+
+            public PlayerResult(
+                    boolean configureSuccess, boolean startSuccess,
+                    boolean decodeSuccess, long totalTime) {
+                this.configureSuccess = configureSuccess;
+                this.startSuccess = startSuccess;
+                this.decodeSuccess = decodeSuccess;
+                this.totalTime = totalTime;
+            }
+
+            public PlayerResult(PlayerResult playerResult) {
+                this(playerResult.configureSuccess, playerResult.startSuccess,
+                        playerResult.decodeSuccess, playerResult.totalTime);
+            }
+
+            public PlayerResult() {
+                // Dummy PlayerResult.
+                this(false, false, false, UNSET);
+            }
+
+            public static PlayerResult failToStart() {
+                return new PlayerResult(true, false, false, UNSET);
+            }
+
+            public boolean isConfigureSuccess() {
+                return configureSuccess;
+            }
+
+            public boolean isStartSuccess() {
+                return startSuccess;
+            }
+
+            public boolean isDecodeSuccess() {
+                return decodeSuccess;
+            }
+
+            public boolean isSuccess() {
+                return isConfigureSuccess() && isStartSuccess()
+                        && isDecodeSuccess() && getTotalTime() != UNSET;
+            }
+
+            public long getTotalTime() {
+                return totalTime;
+            }
+
+            public boolean isFailureForAll() {
+                return (!isConfigureSuccess() && !isStartSuccess()
+                        && !isDecodeSuccess() && getTotalTime() == UNSET);
+            }
+        }
+
+    }
+
+    /* Utility class for collecting common test case functionality. */
+    class TestHelper {
+
+        private final Context context;
+        private final Handler handler;
+        private final Activity activity;
+
+        public TestHelper(Context context, Activity activity) {
+            this.context = checkNotNull(context);
+            this.handler = new Handler(Looper.getMainLooper());
+            this.activity = activity;
+        }
+
+        public Bitmap generateBitmapFromImageResourceId(int resourceId) {
+            return BitmapFactory.decodeStream(context.getResources().openRawResource(resourceId));
+        }
+
+        public Context getContext() {
+            return context;
+        }
+
+        public void rotateOrientation() {
+            handler.post(new Runnable() {
+                @Override
+                public void run() {
+                    final int orientation = context.getResources().getConfiguration().orientation;
+                    if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+                        activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+                    } else {
+                        activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+                    }
+                }
+            });
+        }
+
+        public void unsetOrientation() {
+            handler.post(new Runnable() {
+                @Override
+                public void run() {
+                    activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+                }
+            });
+        }
+
+        public void generateView(View view) {
+            RelativeLayout relativeLayout =
+                    (RelativeLayout) activity.findViewById(R.id.attach_view);
+            ViewGenerator viewGenerator = new ViewGenerator(relativeLayout, view);
+            handler.post(viewGenerator);
+        }
+
+        public void cleanUpView(View view) {
+            ViewCleaner viewCleaner = new ViewCleaner(view);
+            handler.post(viewCleaner);
+        }
+
+        public synchronized Bitmap generateBitmapFromVideoViewSnapshot(VideoViewSnapshot snapshot) {
+            handler.post(snapshot);
+            try {
+                while (!snapshot.isBitmapReady()) {
+                    Thread.sleep(100);
+                }
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+            return snapshot.getBitmap();
+        }
+
+        private class ViewGenerator implements Runnable {
+
+            private final View view;
+            private final RelativeLayout relativeLayout;
+
+            public ViewGenerator(RelativeLayout relativeLayout, View view) {
+                this.view = checkNotNull(view);
+                this.relativeLayout = checkNotNull(relativeLayout);
+            }
+
+            @Override
+            public void run() {
+                if (view.getParent() != null) {
+                    ((ViewGroup) view.getParent()).removeView(view);
+                }
+                RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
+                        VideoViewFactory.VIEW_WIDTH, VideoViewFactory.VIEW_HEIGHT);
+                view.setLayoutParams(params);
+                relativeLayout.addView(view);
+            }
+
+        }
+
+        private class ViewCleaner implements Runnable {
+
+            private final View view;
+
+            public ViewCleaner(View view) {
+                this.view = checkNotNull(view);
+            }
+
+            @Override
+            public void run() {
+                if (view.getParent() != null) {
+                    ((ViewGroup) view.getParent()).removeView(view);
+                }
+            }
+
+        }
+
+    }
+
+}
+
+/* Factory for manipulating a {@link View}. */
+abstract class VideoViewFactory {
+
+    public final long VIEW_AVAILABLE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(1);
+    public static final int VIEW_WIDTH = 480;
+    public static final int VIEW_HEIGHT = 360;
+
+    public VideoViewFactory() {}
+
+    public abstract void release();
+
+    public abstract String getName();
+
+    public abstract View createView(Context context);
+
+    public abstract void waitForViewIsAvailable();
+
+    public abstract Surface getSurface();
+
+    public abstract VideoViewSnapshot getVideoViewSnapshot();
+
+}
+
+/* Factory for building a {@link TextureView}. */
+@TargetApi(16)
+class TextureViewFactory extends VideoViewFactory implements TextureView.SurfaceTextureListener {
+
+    private final String TAG = TextureViewFactory.class.getSimpleName();
+    private final Object syncToken = new Object();
+    private TextureView textureView;
+
+    public TextureViewFactory() {}
+
+    @Override
+    public TextureView createView(Context context) {
+        textureView = DecodeAccuracyTestBase.checkNotNull(new TextureView(context));
+        textureView.setSurfaceTextureListener(this);
+        return textureView;
+    }
+
+    @Override
+    public void release() {
+        textureView = null;
+    }
+
+    @Override
+    public String getName() {
+        return "TextureView";
+    }
+
+    @Override
+    public Surface getSurface() {
+        return new Surface(textureView.getSurfaceTexture());
+    }
+
+    @Override
+    public TextureViewSnapshot getVideoViewSnapshot() {
+        return new TextureViewSnapshot(textureView);
+    }
+
+    @Override
+    public void waitForViewIsAvailable() {
+        while (!textureView.isAvailable()) {
+            synchronized (syncToken) {
+                try {
+                    syncToken.wait(VIEW_AVAILABLE_TIMEOUT_MS);
+                } catch (InterruptedException exception) {
+                    Log.e(TAG, "InterruptedException in waitForViewIsAvailable", exception);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
+        synchronized (syncToken) {
+            syncToken.notify();
+        }
+    }
+
+    @Override
+    public void onSurfaceTextureSizeChanged(
+            SurfaceTexture surfaceTexture, int width, int height) {}
+
+    @Override
+    public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
+        return false;
+    }
+
+    @Override
+    public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {}
+
+}
+
+/**
+ * Factory for building EGL and GLES that could render to GLSurfaceView.
+ * {@link GLSurfaceView} {@link EGL10} {@link GLES20}.
+ */
+@TargetApi(16)
+class GLSurfaceViewFactory extends VideoViewFactory {
+
+    private final String TAG = GLSurfaceViewFactory.class.getSimpleName();
+    private final Object surfaceSyncToken = new Object();
+    private final Object snapshotSyncToken = new Object();
+
+    private GLSurfaceViewThread glSurfaceViewThread;
+    private boolean snapshotIsReady = false;
+
+    public GLSurfaceViewFactory() {}
+
+    @Override
+    public void release() {
+        glSurfaceViewThread.release();
+        glSurfaceViewThread = null;
+    }
+
+    @Override
+    public String getName() {
+        return "GLSurfaceView";
+    }
+
+    @Override
+    public View createView(Context context) {
+        // Do all GL rendering in the GL thread.
+        glSurfaceViewThread = new GLSurfaceViewThread();
+        glSurfaceViewThread.start();
+        // No necessary view to display, return null.
+        return null;
+    }
+
+    @Override
+    public void waitForViewIsAvailable() {
+        while (glSurfaceViewThread.getSurface() == null) {
+            synchronized (surfaceSyncToken) {
+                try {
+                    surfaceSyncToken.wait(VIEW_AVAILABLE_TIMEOUT_MS);
+                } catch (InterruptedException exception) {
+                    Log.e(TAG, "InterruptedException in waitForViewIsAvailable", exception);
+                }
+            }
+        }
+    }
+
+    @Override
+    public Surface getSurface() {
+        return glSurfaceViewThread.getSurface();
+    }
+
+    @Override
+    public VideoViewSnapshot getVideoViewSnapshot() {
+        while (!snapshotIsReady) {
+            synchronized (snapshotSyncToken) {
+                try {
+                    snapshotSyncToken.wait(VIEW_AVAILABLE_TIMEOUT_MS);
+                } catch (InterruptedException exception) {
+                    Log.e(TAG, "InterruptedException in getVideoViewSnapshot", exception);
+                }
+            }
+        }
+        return new GLSurfaceViewSnapshot(
+                glSurfaceViewThread.getByteBuffer(), VIEW_WIDTH, VIEW_HEIGHT);
+    }
+
+    /* Does all GL operations. */
+    private class GLSurfaceViewThread extends Thread
+            implements SurfaceTexture.OnFrameAvailableListener {
+
+        private static final int FLOAT_SIZE_BYTES = 4;
+        private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
+        private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
+        private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
+        private FloatBuffer triangleVertices;
+
+        private final float[] triangleVerticesData = {
+                // X, Y, Z, U, V
+                -1.0f, -1.0f, 0, 0.f, 0.f,
+                1.0f, -1.0f, 0, 1.f, 0.f,
+                -1.0f,  1.0f, 0, 0.f, 1.f,
+                1.0f,  1.0f, 0, 1.f, 1.f,
+        };
+
+        private static final String VERTEX_SHADER =
+                "attribute vec4 aPosition;\n"
+                + "attribute vec4 aTextureCoord;\n"
+                + "varying vec2 vTextureCoord;\n"
+                + "void main() {\n"
+                + "    gl_Position = aPosition;\n"
+                + "    vTextureCoord = aTextureCoord.xy;\n"
+                + "}\n";
+
+        private static final String FRAGMENT_SHADER =
+                "#extension GL_OES_EGL_image_external : require\n"
+                + "precision mediump float;\n"      // highp here doesn't seem to matter
+                + "varying vec2 vTextureCoord;\n"
+                + "uniform samplerExternalOES sTexture;\n"
+                + "void main() {\n"
+                + "    gl_FragColor = texture2D(sTexture, vTextureCoord);\n"
+                + "}\n";
+
+        private int glProgram;
+        private int textureID = -1;
+        private int aPositionHandle;
+        private int aTextureHandle;
+        private EGLDisplay eglDisplay = null;
+        private EGLContext eglContext = null;
+        private EGLSurface eglSurface = null;
+        private EGL10 egl10;
+        private Surface surface = null;
+        private SurfaceTexture surfaceTexture;
+        private ByteBuffer byteBuffer;
+
+        public GLSurfaceViewThread() {}
+
+        @Override
+        public void run() {
+            Looper.prepare();
+            triangleVertices = ByteBuffer
+                    .allocateDirect(triangleVerticesData.length * FLOAT_SIZE_BYTES)
+                            .order(ByteOrder.nativeOrder()).asFloatBuffer();
+            triangleVertices.put(triangleVerticesData).position(0);
+
+            eglSetup();
+            makeCurrent();
+            eglSurfaceCreated();
+
+            surfaceTexture = new SurfaceTexture(getTextureId());
+            surfaceTexture.setOnFrameAvailableListener(this);
+            surface = new Surface(surfaceTexture);
+            synchronized (surfaceSyncToken) {
+                surfaceSyncToken.notify();
+            }
+
+            // Store pixels from surface
+            byteBuffer = ByteBuffer.allocateDirect(VIEW_WIDTH * VIEW_HEIGHT * 4);
+            byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
+            Looper.loop();
+        }
+
+        @Override
+        public void onFrameAvailable(SurfaceTexture st) {
+            checkGlError("before updateTexImage");
+            surfaceTexture.updateTexImage();
+            drawFrame();
+            saveFrame();
+            snapshotIsReady = true;
+            synchronized(snapshotSyncToken) {
+                snapshotSyncToken.notify();
+            }
+        }
+
+        /* Prepares EGL to use GLES 2.0 context and a surface that supports pbuffer. */
+        public void eglSetup() {
+            egl10 = (EGL10) EGLContext.getEGL();
+            eglDisplay = egl10.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+            if (eglDisplay == EGL10.EGL_NO_DISPLAY) {
+                throw new RuntimeException("unable to get egl10 display");
+            }
+            int[] version = new int[2];
+            if (!egl10.eglInitialize(eglDisplay, version)) {
+                eglDisplay = null;
+                throw new RuntimeException("unable to initialize egl10");
+            }
+            // Configure EGL for pbuffer and OpenGL ES 2.0, 24-bit RGB.
+            int[] configAttribs = {
+                    EGL10.EGL_RED_SIZE, 8,
+                    EGL10.EGL_GREEN_SIZE, 8,
+                    EGL10.EGL_BLUE_SIZE, 8,
+                    EGL10.EGL_ALPHA_SIZE, 8,
+                    EGL10.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
+                    EGL10.EGL_SURFACE_TYPE, EGL10.EGL_PBUFFER_BIT,
+                    EGL10.EGL_NONE
+            };
+            EGLConfig[] configs = new EGLConfig[1];
+            int[] numConfigs = new int[1];
+            if (!egl10.eglChooseConfig(
+                    eglDisplay, configAttribs, configs, configs.length, numConfigs)) {
+                throw new RuntimeException("unable to find RGB888+recordable ES2 EGL config");
+            }
+            // Configure EGL context for OpenGL ES 2.0.
+            int[] contextAttribs = {
+                    EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
+                    EGL10.EGL_NONE
+            };
+            eglContext = egl10.eglCreateContext(
+                    eglDisplay, configs[0], EGL10.EGL_NO_CONTEXT, contextAttribs);
+            checkEglError("eglCreateContext");
+            if (eglContext == null) {
+                throw new RuntimeException("null context");
+            }
+            // Create a pbuffer surface.
+            int[] surfaceAttribs = {
+                    EGL10.EGL_WIDTH, VIEW_WIDTH,
+                    EGL10.EGL_HEIGHT, VIEW_HEIGHT,
+                    EGL10.EGL_NONE
+            };
+            eglSurface = egl10.eglCreatePbufferSurface(eglDisplay, configs[0], surfaceAttribs);
+            checkEglError("eglCreatePbufferSurface");
+            if (eglSurface == null) {
+                throw new RuntimeException("surface was null");
+            }
+        }
+
+        public void release() {
+            if (eglDisplay != EGL10.EGL_NO_DISPLAY) {
+                egl10.eglMakeCurrent(eglDisplay,
+                        EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
+                egl10.eglDestroySurface(eglDisplay, eglSurface);
+                egl10.eglDestroyContext(eglDisplay, eglContext);
+                egl10.eglTerminate(eglDisplay);
+            }
+            eglDisplay = EGL10.EGL_NO_DISPLAY;
+            eglContext = EGL10.EGL_NO_CONTEXT;
+            eglSurface = EGL10.EGL_NO_SURFACE;
+            surface.release();
+            surfaceTexture.release();
+        }
+
+        /* Makes our EGL context and surface current. */
+        public void makeCurrent() {
+            if (!egl10.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) {
+                throw new RuntimeException("eglMakeCurrent failed");
+            }
+            checkEglError("eglMakeCurrent");
+        }
+
+        /* Call this after the EGL Surface is created and made current. */
+        public void eglSurfaceCreated() {
+            glProgram = createProgram(VERTEX_SHADER, FRAGMENT_SHADER);
+            if (glProgram == 0) {
+                throw new RuntimeException("failed creating program");
+            }
+            aPositionHandle = GLES20.glGetAttribLocation(glProgram, "aPosition");
+            checkLocation(aPositionHandle, "aPosition");
+            aTextureHandle = GLES20.glGetAttribLocation(glProgram, "aTextureCoord");
+            checkLocation(aTextureHandle, "aTextureCoord");
+
+            int[] textures = new int[1];
+            GLES20.glGenTextures(1, textures, 0);
+            checkGlError("glGenTextures");
+            textureID = textures[0];
+            GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureID);
+            checkGlError("glBindTexture");
+
+            GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
+                    GLES20.GL_LINEAR);
+            GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
+                    GLES20.GL_LINEAR);
+            GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S,
+                    GLES20.GL_CLAMP_TO_EDGE);
+            GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T,
+                    GLES20.GL_CLAMP_TO_EDGE);
+            checkGlError("glTexParameter");
+        }
+
+        public void drawFrame() {
+            GLES20.glUseProgram(glProgram);
+            checkGlError("glUseProgram");
+            GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+            checkGlError("glActiveTexture");
+            GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureID);
+            checkGlError("glBindTexture");
+
+            triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
+            GLES20.glVertexAttribPointer(aPositionHandle, 3, GLES20.GL_FLOAT, false,
+                    TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
+            checkGlError("glVertexAttribPointer aPositionHandle");
+            GLES20.glEnableVertexAttribArray(aPositionHandle);
+            checkGlError("glEnableVertexAttribArray aPositionHandle");
+
+            triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
+            GLES20.glVertexAttribPointer(aTextureHandle, 2, GLES20.GL_FLOAT, false,
+                    TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
+            checkGlError("glVertexAttribPointer aTextureHandle");
+            GLES20.glEnableVertexAttribArray(aTextureHandle);
+            checkGlError("glEnableVertexAttribArray aTextureHandle");
+
+            GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
+            checkGlError("glDrawArrays");
+            GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
+        }
+
+        /* Reads the pixels to a ByteBuffer. */
+        public void saveFrame() {
+            byteBuffer.clear();
+            GLES20.glReadPixels(0, 0, VIEW_WIDTH, VIEW_HEIGHT, GLES20.GL_RGBA,
+                    GLES20.GL_UNSIGNED_BYTE, byteBuffer);
+        }
+
+        public int getTextureId() {
+            return textureID;
+        }
+
+        public Surface getSurface() {
+            return surface;
+        }
+
+        public ByteBuffer getByteBuffer() {
+            return byteBuffer;
+        }
+
+        private int loadShader(int shaderType, String source) {
+            int shader = GLES20.glCreateShader(shaderType);
+            checkGlError("glCreateShader type=" + shaderType);
+            GLES20.glShaderSource(shader, source);
+            GLES20.glCompileShader(shader);
+            int[] compiled = new int[1];
+            GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
+
+            if (compiled[0] == 0) {
+                Log.e(TAG, "Could not compile shader " + shaderType + ":");
+                Log.e(TAG, " " + GLES20.glGetShaderInfoLog(shader));
+                GLES20.glDeleteShader(shader);
+                shader = 0;
+            }
+            return shader;
+        }
+
+        private int createProgram(String vertexSource, String fragmentSource) {
+            int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
+            if (vertexShader == 0) {
+                return 0;
+            }
+            int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
+            if (pixelShader == 0) {
+                return 0;
+            }
+            int program = GLES20.glCreateProgram();
+            if (program == 0) {
+                Log.e(TAG, "Could not create program");
+            }
+            GLES20.glAttachShader(program, vertexShader);
+            checkGlError("glAttachShader");
+            GLES20.glAttachShader(program, pixelShader);
+            checkGlError("glAttachShader");
+            GLES20.glLinkProgram(program);
+            int[] linkStatus = new int[1];
+            GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
+
+            if (linkStatus[0] != GLES20.GL_TRUE) {
+                Log.e(TAG, "Could not link program: ");
+                Log.e(TAG, GLES20.glGetProgramInfoLog(program));
+                GLES20.glDeleteProgram(program);
+                program = 0;
+            }
+            return program;
+        }
+
+        private void checkEglError(String msg) {
+            int error;
+            if ((error = egl10.eglGetError()) != EGL10.EGL_SUCCESS) {
+                throw new RuntimeException(msg + ": EGL error: 0x" + Integer.toHexString(error));
+            }
+        }
+
+        public void checkGlError(String op) {
+            int error;
+            if ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
+                Log.e(TAG, op + ": glError " + error);
+                throw new RuntimeException(op + ": glError " + error);
+            }
+        }
+
+        public void checkLocation(int location, String label) {
+            if (location < 0) {
+                throw new RuntimeException("Unable to locate '" + label + "' in program");
+            }
+        }
+    }
+
+}
+
+/* Definition of a VideoViewSnapshot and a runnable to get a bitmap from a view. */
+abstract class VideoViewSnapshot implements Runnable {
+
+    public abstract Bitmap getBitmap();
+
+    public abstract boolean isBitmapReady();
+
+}
+
+/* Runnable to get a bitmap from a texture view on the UI thread via a handler. */
+class TextureViewSnapshot extends VideoViewSnapshot {
+
+    private final TextureView tv;
+    private Bitmap bitmap = null;
+
+    public TextureViewSnapshot(TextureView tv) {
+        this.tv = DecodeAccuracyTestBase.checkNotNull(tv);
+    }
+
+    @Override
+    public synchronized void run() {
+        bitmap = tv.getBitmap();
+    }
+
+    @Override
+    public Bitmap getBitmap() {
+        return bitmap;
+    }
+
+    @Override
+    public boolean isBitmapReady() {
+        return bitmap != null;
+    }
+
+}
+
+/**
+ * Runnable to get a bitmap from a GLSurfaceView on the UI thread via a handler.
+ * Note, because of how the bitmap is captured in GLSurfaceView,
+ * this method does not have to be a runnable.
+ */
+class GLSurfaceViewSnapshot extends VideoViewSnapshot {
+
+    private Bitmap bitmap = null;
+    private ByteBuffer byteBuffer;
+    private final int width;
+    private final int height;
+    private boolean bitmapIsReady = false;
+
+    public GLSurfaceViewSnapshot(ByteBuffer byteBuffer, int width, int height) {
+        this.byteBuffer = DecodeAccuracyTestBase.checkNotNull(byteBuffer);
+        this.width = width;
+        this.height = height;
+    }
+
+    @Override
+    public synchronized void run() {
+        bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        byteBuffer.rewind();
+        bitmap.copyPixelsFromBuffer(byteBuffer);
+        bitmapIsReady = true;
+    }
+
+    @Override
+    public Bitmap getBitmap() {
+        return bitmap;
+    }
+
+    @Override
+    public boolean isBitmapReady() {
+        return bitmapIsReady;
+    }
+
+}
+
+/* Stores information of a video. */
+class VideoFormat {
+
+    public static final int UNSET = -1;
+    public static final String MIMETYPE_UNSET = "UNSET";
+    public static final String MIMETYPE_KEY = "mimeType";
+    public static final String WIDTH_KEY = "width";
+    public static final String HEIGHT_KEY = "height";
+    public static final String FRAMERATE_KEY = "frameRate";
+
+    private final String filename;
+    private Uri uri;
+    private String mimeType = MIMETYPE_UNSET;
+    private int width = UNSET;
+    private int height = UNSET;
+    private int maxWidth = UNSET;
+    private int maxHeight = UNSET;
+
+    public VideoFormat(String filename, Uri uri) {
+        this.filename = filename;
+        this.uri = uri;
+    }
+
+    public VideoFormat(String filename) {
+        this(filename, null);
+    }
+
+    public VideoFormat(VideoFormat videoFormat) {
+        this(videoFormat.filename, videoFormat.uri);
+    }
+
+    public Uri loadUri(Context context) {
+        uri = createCacheFile(context);
+        return uri;
+    }
+
+    public Uri getUri() {
+        return uri;
+    }
+
+    public String getFilename() {
+        return filename;
+    }
+
+    public void setMimeType(String mimeType) {
+        this.mimeType = mimeType;
+    }
+
+    public String getMimeType() {
+        return mimeType;
+    }
+
+    public void setWidth(int width) {
+        this.width = width;
+    }
+
+    public void setMaxWidth(int maxWidth) {
+        this.maxWidth = maxWidth;
+    }
+
+    public int getWidth() {
+        return width;
+    }
+
+    public int getMaxWidth() {
+        return maxWidth;
+    }
+
+    public void setHeight(int height) {
+        this.height = height;
+    }
+
+    public void setMaxHeight(int maxHeight) {
+        this.maxHeight = maxHeight;
+    }
+
+    public int getHeight() {
+        return height;
+    }
+
+    public int getMaxHeight() {
+        return maxHeight;
+    }
+
+    private Uri createCacheFile(Context context) {
+        try {
+            File cacheFile = new File(context.getCacheDir(), filename);
+            if (cacheFile.createNewFile() == false) {
+                cacheFile.delete();
+                cacheFile.createNewFile();
+            }
+            InputStream inputStream = context.getAssets().open(filename);
+            FileOutputStream fileOutputStream = new FileOutputStream(cacheFile);
+            final int bufferSize = 1024 * 512;
+            byte[] buffer = new byte[bufferSize];
+
+            while (inputStream.read(buffer) != -1) {
+                fileOutputStream.write(buffer, 0, bufferSize);
+            }
+            fileOutputStream.close();
+            inputStream.close();
+            return Uri.fromFile(cacheFile);
+        } catch (IOException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+}
+
+/**
+ * Compares bitmaps to determine if they are similar.
+ *
+ * <p>To determine greatest pixel difference we transform each pixel into the
+ * CIE L*a*b* color space. The euclidean distance formula is used to determine pixel differences.
+ */
+class BitmapCompare {
+
+    private static final int RED = 0;
+    private static final int GREEN = 1;
+    private static final int BLUE = 2;
+    private static final int X = 0;
+    private static final int Y = 1;
+    private static final int Z = 2;
+
+    private static SparseArray<double[]> pixelTransformCache = new SparseArray<>();
+
+    private BitmapCompare() {}
+
+    /**
+     * Produces greatest pixel between two bitmaps. Used to determine bitmap similarity.
+     *
+     * @param bitmap1 A bitmap to compare to bitmap2.
+     * @param bitmap2 A bitmap to compare to bitmap1.
+     * @return A {@link Difference} with an integer describing the greatest pixel difference,
+     *     using {@link Integer#MAX_VALUE} for completely different bitmaps, and an optional
+     *     {@link Pair<Integer, Integer>} of the (col, row) pixel coordinate
+     *     where it was first found.
+     */
+    @TargetApi(12)
+    public static Difference computeDifference(Bitmap bitmap1, Bitmap bitmap2) {
+        if ((bitmap1 == null || bitmap2 == null) && bitmap1 != bitmap2) {
+            return new Difference(Integer.MAX_VALUE);
+        }
+        if (bitmap1 == bitmap2 || bitmap1.sameAs(bitmap2)) {
+            return new Difference(0);
+        }
+        if (bitmap1.getHeight() != bitmap2.getHeight() || bitmap1.getWidth() != bitmap2.getWidth()) {
+            return new Difference(Integer.MAX_VALUE);
+        }
+        // Convert all pixels to CIE L*a*b* color space so we can do a direct color comparison using
+        // euclidean distance formula.
+        final double[][] pixels1 = convertRgbToCieLab(bitmap1);
+        final double[][] pixels2 = convertRgbToCieLab(bitmap2);
+        int greatestDifference = 0;
+        int greatestDifferenceIndex = -1;
+        for (int i = 0; i < pixels1.length; i++) {
+            final int difference = euclideanDistance(pixels1[i], pixels2[i]);
+            if (difference > greatestDifference) {
+                greatestDifference = difference;
+                greatestDifferenceIndex = i;
+            }
+        }
+        return new Difference(greatestDifference, Pair.create(
+            greatestDifferenceIndex % bitmap1.getWidth(),
+            greatestDifferenceIndex / bitmap1.getHeight()));
+    }
+
+    private static double[][] convertRgbToCieLab(Bitmap bitmap) {
+        final double[][] result = new double[bitmap.getHeight() * bitmap.getWidth()][3];
+        final int pixels[] = new int[bitmap.getHeight() * bitmap.getWidth()];
+        bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
+        for (int i = 0; i < pixels.length; i++) {
+            final double[] transformedColor = pixelTransformCache.get(pixels[i]);
+            if (transformedColor != null) {
+                result[i] = transformedColor;
+            } else {
+                result[i] = convertXyzToCieLab(convertRgbToXyz(pixels[i]));
+                pixelTransformCache.put(pixels[i], result[i]);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Conversion from RGB to XYZ based algorithm as defined by:
+     * http://www.easyrgb.com/index.php?X=MATH&H=02#text2
+     *
+     * <p><pre>{@code
+     *   var_R = ( R / 255 )        //R from 0 to 255
+     *   var_G = ( G / 255 )        //G from 0 to 255
+     *   var_B = ( B / 255 )        //B from 0 to 255
+     *
+     *   if ( var_R > 0.04045 ) var_R = ( ( var_R + 0.055 ) / 1.055 ) ^ 2.4
+     *   else                   var_R = var_R / 12.92
+     *   if ( var_G > 0.04045 ) var_G = ( ( var_G + 0.055 ) / 1.055 ) ^ 2.4
+     *   else                   var_G = var_G / 12.92
+     *   if ( var_B > 0.04045 ) var_B = ( ( var_B + 0.055 ) / 1.055 ) ^ 2.4
+     *   else                   var_B = var_B / 12.92
+     *
+     *   var_R = var_R * 100
+     *   var_G = var_G * 100
+     *   var_B = var_B * 100
+     *
+     *   // Observer. = 2°, Illuminant = D65
+     *   X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805
+     *   Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722
+     *   Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505
+     * }</pre>
+     *
+     * @param rgbColor A packed int made up of 4 bytes: alpha, red, green, blue.
+     * @return An array of doubles where each value is a component of the XYZ color space.
+     */
+    private static double[] convertRgbToXyz(int rgbColor) {
+        final double[] comp = {Color.red(rgbColor), Color.green(rgbColor), Color.blue(rgbColor)};
+
+        for (int i = 0; i < comp.length; i++) {
+            comp[i] /= 255.0;
+            if (comp[i] > 0.04045) {
+                comp[i] = Math.pow((comp[i] + 0.055) / 1.055, 2.4);
+            } else {
+                comp[i] /= 12.92;
+            }
+            comp[i] *= 100;
+        }
+        final double x = (comp[RED] * 0.4124) + (comp[GREEN] * 0.3576) + (comp[BLUE] * 0.1805);
+        final double y = (comp[RED] * 0.2126) + (comp[GREEN] * 0.7152) + (comp[BLUE] * 0.0722);
+        final double z = (comp[RED] * 0.0193) + (comp[GREEN] * 0.1192) + (comp[BLUE] * 0.9505);
+        return new double[] {x, y, z};
+    }
+
+    /**
+     * Conversion from XYZ to CIE-L*a*b* based algorithm as defined by:
+     * http://www.easyrgb.com/index.php?X=MATH&H=07#text7
+     *
+     * <p><pre>
+     * {@code
+     *   var_X = X / ref_X          //ref_X =  95.047   Observer= 2°, Illuminant= D65
+     *   var_Y = Y / ref_Y          //ref_Y = 100.000
+     *   var_Z = Z / ref_Z          //ref_Z = 108.883
+     *
+     *   if ( var_X > 0.008856 ) var_X = var_X ^ ( 1/3 )
+     *   else                    var_X = ( 7.787 * var_X ) + ( 16 / 116 )
+     *   if ( var_Y > 0.008856 ) var_Y = var_Y ^ ( 1/3 )
+     *   else                    var_Y = ( 7.787 * var_Y ) + ( 16 / 116 )
+     *   if ( var_Z > 0.008856 ) var_Z = var_Z ^ ( 1/3 )
+     *   else                    var_Z = ( 7.787 * var_Z ) + ( 16 / 116 )
+     *
+     *   CIE-L* = ( 116 * var_Y ) - 16
+     *   CIE-a* = 500 * ( var_X - var_Y )
+     *   CIE-b* = 200 * ( var_Y - var_Z )
+     * }
+     * </pre>
+     *
+     * @param comp An array of doubles where each value is a component of the XYZ color space.
+     * @return An array of doubles where each value is a component of the CIE-L*a*b* color space.
+     */
+    private static double[] convertXyzToCieLab(double[] comp) {
+        comp[X] /= 95.047;
+        comp[Y] /= 100.0;
+        comp[Z] /= 108.883;
+
+        for (int i = 0; i < comp.length; i++) {
+            if (comp[i] > 0.008856) {
+                comp[i] = Math.pow(comp[i], (1.0 / 3.0));
+            } else {
+                comp[i] = (7.787 * comp[i]) + (16.0 / 116.0);
+            }
+        }
+        final double l = (116 * comp[Y]) - 16;
+        final double a = 500 * (comp[X] - comp[Y]);
+        final double b = 200 * (comp[Y] - comp[Z]);
+        return new double[] {l, a, b};
+    }
+
+    private static int euclideanDistance(double[] p1, double[] p2) {
+        if (p1.length != p2.length) {
+            return Integer.MAX_VALUE;
+        }
+        double result = 0;
+        for (int i = 0; i < p1.length; i++) {
+            result += Math.pow(p1[i] - p2[i], 2);
+        }
+        return (int) Math.round(Math.sqrt(result));
+    }
+
+    /* Describes the difference between two {@link Bitmap} instances. */
+    public static final class Difference {
+
+        public final int greatestPixelDifference;
+        public final Pair<Integer, Integer> greatestPixelDifferenceCoordinates;
+
+        private Difference(int greatestPixelDifference) {
+            this(greatestPixelDifference, null);
+        }
+
+        private Difference(
+                int greatestPixelDifference,
+                Pair<Integer, Integer> greatestPixelDifferenceCoordinates) {
+            this.greatestPixelDifference = greatestPixelDifference;
+            this.greatestPixelDifferenceCoordinates = greatestPixelDifferenceCoordinates;
+        }
+    }
+
+}
+
+/* Wrapper for MIME types. */
+final class MimeTypes {
+
+    private MimeTypes() {}
+
+    public static final String VIDEO_VP9 = "video/x-vnd.on2.vp9";
+    public static final String VIDEO_H264 = "video/avc";
+
+    public static boolean isVideo(String mimeType) {
+        return mimeType.startsWith("video");
+    }
+
+}
diff --git a/tests/tests/media/src/android/media/cts/DecoderTest.java b/tests/tests/media/src/android/media/cts/DecoderTest.java
index f6c1a0c..f4e259c 100755
--- a/tests/tests/media/src/android/media/cts/DecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTest.java
@@ -176,6 +176,14 @@
         testTimeStampOrdering(R.raw.sinesweeptsaac);
     }
 
+    public void testDecodeVorbis() throws Exception {
+        testTimeStampOrdering(R.raw.sinesweepvorbis);
+    }
+
+    public void testDecodeOpus() throws Exception {
+        testTimeStampOrdering(R.raw.sinesweepopus);
+    }
+
     public void testDecode51M4a() throws Exception {
         decodeToMemory(R.raw.sinesweep51m4a, RESET_MODE_NONE, CONFIG_MODE_NONE, -1, null);
     }
diff --git a/tests/tests/media/src/android/media/cts/EncoderTest.java b/tests/tests/media/src/android/media/cts/EncoderTest.java
index be6ed48..e48af7e 100644
--- a/tests/tests/media/src/android/media/cts/EncoderTest.java
+++ b/tests/tests/media/src/android/media/cts/EncoderTest.java
@@ -271,6 +271,8 @@
         // test with pcm input file
         testEncoder(componentName, format, 0, R.raw.okgoogle123_good, MODE_RESOURCE);
         testEncoder(componentName, format, 0, R.raw.okgoogle123_good, MODE_RESOURCE | MODE_QUIET);
+        testEncoder(componentName, format, 0, R.raw.tones, MODE_RESOURCE);
+        testEncoder(componentName, format, 0, R.raw.tones, MODE_RESOURCE | MODE_QUIET);
 
         // test with random data, with and without a few leading zeroes
         for (int i = 0; i < mBadSeeds.length; i++) {
diff --git a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
index fc4a42a..dff6b1c 100644
--- a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
+++ b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
@@ -57,7 +57,7 @@
     private static final String[] EXIF_TAGS = {
             ExifInterface.TAG_MAKE,
             ExifInterface.TAG_MODEL,
-            ExifInterface.TAG_APERTURE,
+            ExifInterface.TAG_F_NUMBER,
             ExifInterface.TAG_DATETIME,
             ExifInterface.TAG_EXPOSURE_TIME,
             ExifInterface.TAG_FLASH,
@@ -73,7 +73,7 @@
             ExifInterface.TAG_GPS_TIMESTAMP,
             ExifInterface.TAG_IMAGE_LENGTH,
             ExifInterface.TAG_IMAGE_WIDTH,
-            ExifInterface.TAG_ISO,
+            ExifInterface.TAG_ISO_SPEED_RATINGS,
             ExifInterface.TAG_ORIENTATION,
             ExifInterface.TAG_WHITE_BALANCE
     };
@@ -295,7 +295,7 @@
         // Checks values.
         assertStringTag(exifInterface, ExifInterface.TAG_MAKE, expectedValue.make);
         assertStringTag(exifInterface, ExifInterface.TAG_MODEL, expectedValue.model);
-        assertFloatTag(exifInterface, ExifInterface.TAG_APERTURE, expectedValue.aperture);
+        assertFloatTag(exifInterface, ExifInterface.TAG_F_NUMBER, expectedValue.aperture);
         assertStringTag(exifInterface, ExifInterface.TAG_DATETIME, expectedValue.datetime);
         assertFloatTag(exifInterface, ExifInterface.TAG_EXPOSURE_TIME, expectedValue.exposureTime);
         assertFloatTag(exifInterface, ExifInterface.TAG_FLASH, expectedValue.flash);
@@ -315,7 +315,7 @@
         assertStringTag(exifInterface, ExifInterface.TAG_GPS_TIMESTAMP, expectedValue.gpsTimestamp);
         assertIntTag(exifInterface, ExifInterface.TAG_IMAGE_LENGTH, expectedValue.imageLength);
         assertIntTag(exifInterface, ExifInterface.TAG_IMAGE_WIDTH, expectedValue.imageWidth);
-        assertStringTag(exifInterface, ExifInterface.TAG_ISO, expectedValue.iso);
+        assertStringTag(exifInterface, ExifInterface.TAG_ISO_SPEED_RATINGS, expectedValue.iso);
         assertIntTag(exifInterface, ExifInterface.TAG_ORIENTATION, expectedValue.orientation);
         assertIntTag(exifInterface, ExifInterface.TAG_WHITE_BALANCE, expectedValue.whiteBalance);
     }
diff --git a/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java b/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
index 3e8458b..d9e6816 100644
--- a/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
@@ -47,7 +47,7 @@
         }
     };
 
-    private final MediaBrowser.SubscriptionCallback mSubscriptionCallback  =
+    private final MediaBrowser.SubscriptionCallback mSubscriptionCallback =
             new MediaBrowser.SubscriptionCallback() {
             @Override
             public void onChildrenLoaded(String parentId, List<MediaItem> children) {
@@ -56,10 +56,18 @@
                     mWaitLock.notify();
                 }
             }
+
+            @Override
+            public void onChildrenLoaded(String parentId, List<MediaItem> children,
+                    Bundle options) {
+                synchronized (mWaitLock) {
+                    mOnChildrenLoadedWithOptions = true;
+                    mWaitLock.notify();
+                }
+            }
         };
 
-    private final MediaBrowser.ItemCallback mItemCallback  =
-            new MediaBrowser.ItemCallback() {
+    private final MediaBrowser.ItemCallback mItemCallback = new MediaBrowser.ItemCallback() {
         @Override
         public void onItemLoaded(MediaItem item) {
             synchronized (mWaitLock) {
@@ -72,6 +80,7 @@
     private MediaBrowser mMediaBrowser;
     private StubMediaBrowserService mMediaBrowserService;
     private boolean mOnChildrenLoaded;
+    private boolean mOnChildrenLoadedWithOptions;
     private boolean mOnItemLoaded;
 
     @Override
@@ -108,6 +117,26 @@
         }
     }
 
+    public void testNotifyChildrenChangedWithPagination() throws Exception {
+        synchronized (mWaitLock) {
+            final int pageSize = 5;
+            final int page = 2;
+            Bundle options = new Bundle();
+            options.putInt(MediaBrowser.EXTRA_PAGE_SIZE, pageSize);
+            options.putInt(MediaBrowser.EXTRA_PAGE, page);
+
+            mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, options,
+                    mSubscriptionCallback);
+            mWaitLock.wait(TIME_OUT_MS);
+            assertTrue(mOnChildrenLoadedWithOptions);
+
+            mOnChildrenLoadedWithOptions = false;
+            mMediaBrowserService.notifyChildrenChanged(StubMediaBrowserService.MEDIA_ID_ROOT);
+            mWaitLock.wait(TIME_OUT_MS);
+            assertTrue(mOnChildrenLoadedWithOptions);
+        }
+    }
+
     public void testDelayedNotifyChildrenChanged() throws Exception {
         synchronized (mWaitLock) {
             mOnChildrenLoaded = false;
diff --git a/tests/tests/media/src/android/media/cts/MediaBrowserTest.java b/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
index 399a4e6..23f464e 100644
--- a/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
@@ -122,11 +122,10 @@
         createMediaBrowser(TEST_BROWSER_SERVICE);
         connectMediaBrowserService();
         final int pageSize = 3;
-        final int lastPage = (StubMediaBrowserService.MEDIA_ID_CHILDREN.length + pageSize - 1)
-                / pageSize;
+        final int lastPage = (StubMediaBrowserService.MEDIA_ID_CHILDREN.length - 1) / pageSize;
         Bundle options = new Bundle();
         options.putInt(MediaBrowser.EXTRA_PAGE_SIZE, pageSize);
-        for (int page = 1; page <= lastPage; ++page) {
+        for (int page = 0; page <= lastPage; ++page) {
             resetCallbacks();
             options.putInt(MediaBrowser.EXTRA_PAGE, page);
             mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, options,
@@ -142,12 +141,12 @@
             if (page != lastPage) {
                 assertEquals(pageSize, mSubscriptionCallback.mLastChildMediaItems.size());
             } else {
-                assertEquals((StubMediaBrowserService.MEDIA_ID_CHILDREN.length + pageSize - 1)
-                        % pageSize + 1, mSubscriptionCallback.mLastChildMediaItems.size());
+                assertEquals((StubMediaBrowserService.MEDIA_ID_CHILDREN.length - 1) % pageSize + 1,
+                        mSubscriptionCallback.mLastChildMediaItems.size());
             }
             // Check whether all the items in the current page are loaded.
             for (int i = 0; i < mSubscriptionCallback.mLastChildMediaItems.size(); ++i) {
-                assertEquals(StubMediaBrowserService.MEDIA_ID_CHILDREN[(page - 1) * pageSize + i],
+                assertEquals(StubMediaBrowserService.MEDIA_ID_CHILDREN[page * pageSize + i],
                         mSubscriptionCallback.mLastChildMediaItems.get(i).getMediaId());
             }
         }
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java b/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java
index 129bfea..1d95463 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java
@@ -18,6 +18,7 @@
 import android.content.res.Resources;
 import android.content.res.AssetFileDescriptor;
 import android.media.AudioManager;
+import android.media.DrmInitData;
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
 import android.media.MediaCodecList;
@@ -77,7 +78,6 @@
     private Thread mThread;
     private Uri mAudioUri;
     private Uri mVideoUri;
-    private String mDrmInitDataType;
     private Resources mResources;
 
     private static final byte[] PSSH = hexStringToByteArray(
@@ -108,10 +108,9 @@
      * Media player class to stream CENC content using MediaCodec class.
      */
     public MediaCodecClearKeyPlayer(
-            SurfaceHolder holder, byte[] sessionId, String initDataType, Resources resources) {
+            SurfaceHolder holder, byte[] sessionId, Resources resources) {
         mSessionId = sessionId;
         mSurfaceHolder = holder;
-        mDrmInitDataType = initDataType;
         mResources = resources;
         mState = STATE_IDLE;
         mThread = new Thread(new Runnable() {
@@ -152,41 +151,19 @@
         return mMediaFormatWidth;
     }
 
-    public final Map<UUID, byte[]> getPsshInfo() {
-        if (mVideoExtractor != null) {
-            mPsshInitData = mVideoExtractor.getPsshInfo();
-        }
-        // TODO (edwinwong@)
-        // Remove the if statement when we get content that has the clear key system id.
-        if (mPsshInitData == null ||
-                (mPsshInitData != null && !mPsshInitData.containsKey(CLEARKEY_SCHEME_UUID))) {
-            mPsshInitData = new HashMap<UUID, byte[]>();
-            mPsshInitData.put(CLEARKEY_SCHEME_UUID, PSSH);
-        }
-        return mPsshInitData;
-    }
-
     public final byte[] getDrmInitData() {
-        if ("cenc".equals(mDrmInitDataType)) {
-            return getPsshInfo().get(CLEARKEY_SCHEME_UUID);
-        } else if ("webm".equals(mDrmInitDataType)) {
-            for (MediaExtractor ex: new MediaExtractor[] {mVideoExtractor, mAudioExtractor}) {
-                for (int i = ex.getTrackCount(); i-- > 0;) {
-                    MediaFormat format = ex.getTrackFormat(i);
-                    // TODO use public api if possible
-                    ByteBuffer cryptoKey = format.getByteBuffer("crypto-key");
-                    if (cryptoKey != null) {
-                        byte[] dst = new byte[cryptoKey.remaining()];
-                        cryptoKey.get(dst);
-                        return dst;
-                    }
+        for (MediaExtractor ex: new MediaExtractor[] {mVideoExtractor, mAudioExtractor}) {
+            DrmInitData drmInitData = ex.getDrmInitData();
+            if (drmInitData != null) {
+                DrmInitData.SchemeInitData schemeInitData = drmInitData.get(CLEARKEY_SCHEME_UUID);
+                if (schemeInitData != null && schemeInitData.data != null) {
+                    return schemeInitData.data;
                 }
             }
-            return new byte[0];
-        } else {
-          throw new IllegalArgumentException(
-                  "initDataType must be one of {\"cenc\", \"webm\"}: " + mDrmInitDataType);
         }
+        // TODO
+        // Should not happen after we get content that has the clear key system id.
+        return PSSH;
     }
 
     private void prepareAudio() throws IOException {
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
index 1d0ab26..4eaefc3 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
@@ -688,55 +688,63 @@
     }
 
     private void testGapless(int resid1, int resid2) throws Exception {
-
-        MediaPlayer mp1 = new MediaPlayer();
-        mp1.setAudioStreamType(AudioManager.STREAM_MUSIC);
+        MediaPlayer mp1 = null;
+        MediaPlayer mp2 = null;
+        AudioEffect vc = null;
+        Visualizer vis = null;
+        AudioManager am = null;
+        int oldRingerMode = Integer.MIN_VALUE;
+        int oldVolume = Integer.MIN_VALUE;
         try {
+            Utils.toggleNotificationPolicyAccess(
+                    mContext.getPackageName(), getInstrumentation(), true /* on */);
+
+            mp1 = new MediaPlayer();
+            mp1.setAudioStreamType(AudioManager.STREAM_MUSIC);
+
             AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(resid1);
             mp1.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
             afd.close();
             mp1.prepare();
-        } catch (Exception e) {
-            assertTrue(false);
-        }
-        int session = mp1.getAudioSessionId();
 
-        MediaPlayer mp2 = new MediaPlayer();
-        mp2.setAudioSessionId(session);
-        mp2.setAudioStreamType(AudioManager.STREAM_MUSIC);
-        try {
-            AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(resid2);
+            int session = mp1.getAudioSessionId();
+
+            mp2 = new MediaPlayer();
+            mp2.setAudioSessionId(session);
+            mp2.setAudioStreamType(AudioManager.STREAM_MUSIC);
+
+            afd = mContext.getResources().openRawResourceFd(resid2);
             mp2.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
             afd.close();
             mp2.prepare();
-        } catch (Exception e) {
-            assertTrue(false);
-        }
-        // creating a volume controller on output mix ensures that ro.audio.silent mutes
-        // audio after the effects and not before
-        AudioEffect vc = new AudioEffect(
+
+            // creating a volume controller on output mix ensures that ro.audio.silent mutes
+            // audio after the effects and not before
+            vc = new AudioEffect(
                             AudioEffect.EFFECT_TYPE_NULL,
                             UUID.fromString("119341a0-8469-11df-81f9-0002a5d5c51b"),
                             0,
                             session);
-        vc.setEnabled(true);
-        int captureintervalms = mp1.getDuration() + mp2.getDuration() - 2000;
-        int size = 256;
-        int[] range = Visualizer.getCaptureSizeRange();
-        if (size < range[0]) {
-            size = range[0];
-        }
-        if (size > range[1]) {
-            size = range[1];
-        }
-        byte [] vizdata = new byte[size];
-        Visualizer vis = new Visualizer(session);
-        AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-        int oldRingerMode = am.getRingerMode();
-        am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
-        int oldvolume = am.getStreamVolume(AudioManager.STREAM_MUSIC);
-        am.setStreamVolume(AudioManager.STREAM_MUSIC, 1, 0);
-        try {
+            vc.setEnabled(true);
+            int captureintervalms = mp1.getDuration() + mp2.getDuration() - 2000;
+            int size = 256;
+            int[] range = Visualizer.getCaptureSizeRange();
+            if (size < range[0]) {
+                size = range[0];
+            }
+            if (size > range[1]) {
+                size = range[1];
+            }
+            byte[] vizdata = new byte[size];
+
+            vis = new Visualizer(session);
+            am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+            oldRingerMode = am.getRingerMode();
+            // make sure we aren't in silent mode
+            am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+            oldVolume = am.getStreamVolume(AudioManager.STREAM_MUSIC);
+            am.setStreamVolume(AudioManager.STREAM_MUSIC, 1, 0);
+
             assertEquals("setCaptureSize failed",
                     Visualizer.SUCCESS, vis.setCaptureSize(vizdata.length));
             assertEquals("setEnabled failed", Visualizer.SUCCESS, vis.setEnabled(true));
@@ -770,12 +778,26 @@
                 first = false;
             }
         } finally {
-            mp1.release();
-            mp2.release();
-            vis.release();
-            vc.release();
-            am.setRingerMode(oldRingerMode);
-            am.setStreamVolume(AudioManager.STREAM_MUSIC, oldvolume, 0);
+            if (mp1 != null) {
+                mp1.release();
+            }
+            if (mp2 != null) {
+                mp2.release();
+            }
+            if (vis != null) {
+                vis.release();
+            }
+            if (vc != null) {
+                vc.release();
+            }
+            if (oldRingerMode != Integer.MIN_VALUE) {
+                am.setRingerMode(oldRingerMode);
+            }
+            if (oldVolume != Integer.MIN_VALUE) {
+                am.setStreamVolume(AudioManager.STREAM_MUSIC, oldVolume, 0);
+            }
+            Utils.toggleNotificationPolicyAccess(
+                    mContext.getPackageName(), getInstrumentation(), false  /* on == false */);
         }
     }
 
diff --git a/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java b/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java
index 0272298..952e03f 100644
--- a/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java
@@ -48,10 +48,10 @@
 
         FileCopyHelper copier = new FileCopyHelper(mContext);
         String fileName = "test" + System.currentTimeMillis();
-        copier.copy(R.raw.testmp3, fileName);
-
-        File dir = getContext().getFilesDir();
+        File dir = getContext().getExternalFilesDir(null);
         mMediaFile = new File(dir, fileName);
+        copier.copyToExternalStorage(R.raw.testmp3, mMediaFile);
+
         assertTrue(mMediaFile.exists());
     }
 
diff --git a/tests/tests/media/src/android/media/cts/MediaSyncTest.java b/tests/tests/media/src/android/media/cts/MediaSyncTest.java
index e211682..bdd190f 100644
--- a/tests/tests/media/src/android/media/cts/MediaSyncTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaSyncTest.java
@@ -82,8 +82,10 @@
     private boolean mHasVideo = false;
     private boolean mEosAudio = false;
     private boolean mEosVideo = false;
+    private int mTaggedAudioBufferIndex = -1;
     private final Object mConditionEos = new Object();
     private final Object mConditionEosAudio = new Object();
+    private final Object mConditionTaggedAudioBufferIndex = new Object();
 
     private int mNumBuffersReturned = 0;
 
@@ -138,15 +140,23 @@
         return ((!mHasVideo || mEosVideo) && (!mHasAudio || mEosAudio));
     }
 
+    public void onTaggedAudioBufferIndex(Decoder decoder, int index) {
+        synchronized (mConditionTaggedAudioBufferIndex) {
+            if (decoder == mDecoderAudio) {
+                mTaggedAudioBufferIndex = index;
+            }
+        }
+    }
+
     public void onEos(Decoder decoder) {
-        synchronized(mConditionEosAudio) {
+        synchronized (mConditionEosAudio) {
             if (decoder == mDecoderAudio) {
                 mEosAudio = true;
                 mConditionEosAudio.notify();
             }
         }
 
-        synchronized(mConditionEos) {
+        synchronized (mConditionEos) {
             if (decoder == mDecoderVideo) {
                 mEosVideo = true;
             }
@@ -173,7 +183,7 @@
         }
 
         assertTrue("The stream in test file can not be decoded",
-                mDecoderAudio.setup(INPUT_RESOURCE_ID, null, Long.MAX_VALUE));
+                mDecoderAudio.setup(INPUT_RESOURCE_ID, null, Long.MAX_VALUE, NO_TIMESTAMP));
 
         // get audio track.
         mAudioTrack = mDecoderAudio.getAudioTrack();
@@ -222,7 +232,7 @@
         final Object condition = new Object();
 
         mHasAudio = true;
-        if (mDecoderAudio.setup(inputResourceId, null, Long.MAX_VALUE) == false) {
+        if (mDecoderAudio.setup(inputResourceId, null, Long.MAX_VALUE, NO_TIMESTAMP) == false) {
             return true;
         }
 
@@ -283,7 +293,7 @@
         returnedIndex[0] = -1;
 
         mHasAudio = true;
-        if (mDecoderAudio.setup(inputResourceId, null, Long.MAX_VALUE) == false) {
+        if (mDecoderAudio.setup(inputResourceId, null, Long.MAX_VALUE, NO_TIMESTAMP) == false) {
             return true;
         }
 
@@ -417,8 +427,8 @@
             boolean audio,
             boolean video,
             float playbackRate) {
-        // allow 250ms for playback to get to stable state.
-        final int PLAYBACK_RAMP_UP_TIME_MS = 250;
+        // allow 750ms for playback to get to stable state.
+        final int PLAYBACK_RAMP_UP_TIME_US = 750000;
 
         final Object conditionFirstAudioBuffer = new Object();
 
@@ -427,14 +437,16 @@
             mSurface = mMediaSync.createInputSurface();
 
             if (mDecoderVideo.setup(
-                    inputResourceId, mSurface, lastBufferTimestampUs) == false) {
+                    inputResourceId, mSurface, lastBufferTimestampUs, NO_TIMESTAMP) == false) {
                 return true;
             }
             mHasVideo = true;
         }
 
         if (audio) {
-            if (mDecoderAudio.setup(inputResourceId, null, lastBufferTimestampUs) == false) {
+            if (mDecoderAudio.setup(
+                    inputResourceId, null, lastBufferTimestampUs,
+                    PLAYBACK_RAMP_UP_TIME_US) == false) {
                 return true;
             }
 
@@ -452,7 +464,12 @@
                         decoderAudio.releaseOutputBuffer(bufferIndex, NO_TIMESTAMP);
                     }
                     synchronized (conditionFirstAudioBuffer) {
-                        conditionFirstAudioBuffer.notify();
+                        synchronized (mConditionTaggedAudioBufferIndex) {
+                            if (mTaggedAudioBufferIndex >= 0
+                                    && mTaggedAudioBufferIndex == bufferIndex) {
+                                conditionFirstAudioBuffer.notify();
+                            }
+                        }
                     }
                 }
             }, null);
@@ -484,13 +501,6 @@
         }
 
         if (audio) {
-            try {
-                Thread.sleep(PLAYBACK_RAMP_UP_TIME_MS);
-            } catch (InterruptedException e) {
-                Log.i(LOG_TAG, "worker thread is interrupted during sleeping.");
-                return true;
-            }
-
             MediaTimestamp mediaTimestamp = mMediaSync.getTimestamp();
             assertTrue("No timestamp available for starting", mediaTimestamp != null);
             long checkStartTimeRealUs = System.nanoTime() / 1000;
@@ -542,6 +552,7 @@
         private MediaSync mMediaSync = null;
         private boolean mIsAudio = false;
         private long mLastBufferTimestampUs = 0;
+        private long mStartingAudioTimestampUs = NO_TIMESTAMP;
 
         private Surface mSurface = null;
 
@@ -577,7 +588,9 @@
             mIsAudio = isAudio;
         }
 
-        public boolean setup(int inputResourceId, Surface surface, long lastBufferTimestampUs) {
+        public boolean setup(
+                int inputResourceId, Surface surface, long lastBufferTimestampUs,
+                long startingAudioTimestampUs) {
             if (!mIsAudio) {
                 mSurface = surface;
                 // handle video callback in a separate thread as releaseOutputBuffer is blocking
@@ -586,6 +599,7 @@
                 mHandler = new Handler(mHandlerThread.getLooper());
             }
             mLastBufferTimestampUs = lastBufferTimestampUs;
+            mStartingAudioTimestampUs = startingAudioTimestampUs;
             try {
                 // get extrator.
                 String type = mIsAudio ? "audio/" : "video/";
@@ -728,13 +742,18 @@
                 if (info.size > 0) {
                     if (mIsAudio) {
                         ByteBuffer outputByteBuffer = codec.getOutputBuffer(index);
-                        synchronized(mAudioBufferLock) {
+                        synchronized (mAudioBufferLock) {
                             mAudioBuffers.add(new AudioBuffer(outputByteBuffer, index));
                         }
                         mMediaSync.queueAudio(
                                 outputByteBuffer,
                                 index,
                                 info.presentationTimeUs);
+                        if (mStartingAudioTimestampUs >= 0
+                                && info.presentationTimeUs >= mStartingAudioTimestampUs) {
+                            mMediaSyncTest.onTaggedAudioBufferIndex(this, index);
+                            mStartingAudioTimestampUs = NO_TIMESTAMP;
+                        }
                     } else {
                         codec.releaseOutputBuffer(index, info.presentationTimeUs * 1000);
                     }
@@ -753,7 +772,7 @@
         }
 
         public void checkReturnedAudioBuffer(ByteBuffer byteBuffer, int bufferIndex) {
-            synchronized(mAudioBufferLock) {
+            synchronized (mAudioBufferLock) {
                 AudioBuffer audioBuffer = mAudioBuffers.get(0);
                 if (audioBuffer.mByteBuffer != byteBuffer
                         || audioBuffer.mBufferIndex != bufferIndex) {
diff --git a/tests/tests/media/src/android/media/cts/RingtoneTest.java b/tests/tests/media/src/android/media/cts/RingtoneTest.java
index 3527b1a..de21bdd 100644
--- a/tests/tests/media/src/android/media/cts/RingtoneTest.java
+++ b/tests/tests/media/src/android/media/cts/RingtoneTest.java
@@ -54,7 +54,14 @@
         mAudioManager.setStreamVolume(AudioManager.STREAM_RING, maxVolume / 2,
                 AudioManager.FLAG_ALLOW_RINGER_MODES);
         // make sure that we are not in silent mode
-        mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+        try {
+            Utils.toggleNotificationPolicyAccess(
+                    mContext.getPackageName(), getInstrumentation(), true);
+            mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+        } finally {
+            Utils.toggleNotificationPolicyAccess(
+                    mContext.getPackageName(), getInstrumentation(), false);
+        }
 
         mDefaultRingUri = RingtoneManager.getActualDefaultRingtoneUri(mContext,
                 RingtoneManager.TYPE_RINGTONE);
@@ -80,7 +87,14 @@
             mRingtone.setStreamType(mOriginalStreamType);
         }
         if (mAudioManager != null) {
-            mAudioManager.setRingerMode(mOriginalRingerMode);
+            try {
+                Utils.toggleNotificationPolicyAccess(
+                        mContext.getPackageName(), getInstrumentation(), true);
+                mAudioManager.setRingerMode(mOriginalRingerMode);
+            } finally {
+                Utils.toggleNotificationPolicyAccess(
+                        mContext.getPackageName(), getInstrumentation(), false);
+            }
             mAudioManager.setStreamVolume(AudioManager.STREAM_RING, mOriginalVolume,
                     AudioManager.FLAG_ALLOW_RINGER_MODES);
         }
diff --git a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
index 9a99c22..6ed4368 100644
--- a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -265,13 +265,16 @@
         }
 
         // We will register for a WIFI network being available or lost.
-        NetworkRequest request = new NetworkRequest.Builder()
+        final NetworkRequest request = new NetworkRequest.Builder()
                 .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                 .build();
-        TestNetworkCallback callback = new TestNetworkCallback();
+        final TestNetworkCallback callback = new TestNetworkCallback();
         mCm.registerNetworkCallback(request, callback);
 
-        boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
+        final TestNetworkCallback defaultTrackingCallback = new TestNetworkCallback();
+        mCm.registerDefaultNetworkCallback(defaultTrackingCallback);
+
+        final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
 
         try {
             // Make sure WiFi is connected to an access point to start with.
@@ -284,12 +287,16 @@
             // is registered.
             assertTrue("Did not receive NetworkCallback.onAvailable for TRANSPORT_WIFI",
                     callback.waitForAvailable());
+
+            assertTrue("Did not receive NetworkCallback.onAvailable for any default network",
+                    defaultTrackingCallback.waitForAvailable());
         } catch (InterruptedException e) {
             fail("Broadcast receiver or NetworkCallback wait was interrupted.");
         } finally {
             mCm.unregisterNetworkCallback(callback);
+            mCm.unregisterNetworkCallback(defaultTrackingCallback);
 
-            // Return WiFI to its original enabled/disabled state.
+            // Return WiFi to its original enabled/disabled state.
             if (!previousWifiEnabledState) {
                 disconnectFromWifi();
             }
@@ -327,7 +334,7 @@
                 .build();
         mCm.registerNetworkCallback(request, pendingIntent);
 
-        boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
+        final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
 
         try {
             // Make sure WiFi is connected to an access point to start with.
@@ -347,7 +354,7 @@
             pendingIntent.cancel();
             mContext.unregisterReceiver(receiver);
 
-            // Return WiFI to its original enabled/disabled state.
+            // Return WiFi to its original enabled/disabled state.
             if (!previousWifiEnabledState) {
                 disconnectFromWifi();
             }
diff --git a/tests/tests/os/AndroidManifest.xml b/tests/tests/os/AndroidManifest.xml
index deb7045..bdb5230 100644
--- a/tests/tests/os/AndroidManifest.xml
+++ b/tests/tests/os/AndroidManifest.xml
@@ -16,7 +16,7 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.os">
+    package="android.os.cts">
 
     <permission android:name="android.os.cts.permission.TEST_GRANTED"
         android:protectionLevel="normal"
@@ -132,7 +132,7 @@
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                     android:targetPackage="com.android.cts.os"
+                     android:targetPackage="android.os.cts"
                      android:label="CTS tests of android.os">
         <meta-data android:name="listener"
             android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/os/AndroidTest.xml b/tests/tests/os/AndroidTest.xml
index 1676c88..fd446c2 100644
--- a/tests/tests/os/AndroidTest.xml
+++ b/tests/tests/os/AndroidTest.xml
@@ -19,7 +19,7 @@
         <option name="test-file-name" value="CtsOsTestCases.apk" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="com.android.cts.os" />
+        <option name="package" value="android.os.cts" />
         <option name="runtime-hint" value="3m15s" />
     </test>
 </configuration>
diff --git a/tests/tests/os/jni/Android.mk b/tests/tests/os/jni/Android.mk
index 3305fc9..6d2f1dd 100644
--- a/tests/tests/os/jni/Android.mk
+++ b/tests/tests/os/jni/Android.mk
@@ -28,9 +28,37 @@
 		android_os_cts_HardwareName.cpp \
 		android_os_cts_OSFeatures.cpp \
 		android_os_cts_NoExecutePermissionTest.cpp \
-		android_os_cts_SeccompTest.cpp \
-		seccomp-tests/tests/seccomp_bpf_tests.c \
-		seccomp_sample_program.cpp
+		android_os_cts_SeccompTest.cpp
+
+# Select the architectures on which seccomp-bpf are supported. This is used to
+# include extra test files that will not compile on architectures where it is
+# not supported.
+ARCH_SUPPORTS_SECCOMP := 0
+ifeq ($(strip $(TARGET_ARCH)),arm)
+	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
+
+ifeq ($(strip $(TARGET_ARCH)),x86_64)
+	ARCH_SUPPORTS_SECCOMP = 1
+endif
+
+ifeq ($(ARCH_SUPPORTS_SECCOMP),1)
+	LOCAL_SRC_FILES += seccomp-tests/tests/seccomp_bpf_tests.c \
+			seccomp_sample_program.cpp
+
+	# This define controls the behavior of OSFeatures.needsSeccompSupport().
+	LOCAL_CFLAGS += -DARCH_SUPPORTS_SECCOMP
+endif
 
 LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
 
diff --git a/tests/tests/os/jni/android_os_cts_OSFeatures.cpp b/tests/tests/os/jni/android_os_cts_OSFeatures.cpp
index f734bab..153fb27 100644
--- a/tests/tests/os/jni/android_os_cts_OSFeatures.cpp
+++ b/tests/tests/os/jni/android_os_cts_OSFeatures.cpp
@@ -82,13 +82,42 @@
     return WIFSIGNALED(status) && (WTERMSIG(status) == SIGSYS);
 }
 
+jboolean android_os_cts_OSFeatures_needsSeccompSupport(JNIEnv*, jobject)
+{
+#if !defined(ARCH_SUPPORTS_SECCOMP)
+    // Seccomp support is only available for ARM, x86, x86_64.
+    // This define is controlled by the Android.mk.
+    return false;
+#endif
+
+    int major;
+    int minor;
+    struct utsname uts;
+    if (uname(&uts) == -1) {
+        return false;
+    }
+
+    if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
+        return false;
+    }
+
+    // Kernels before 3.8 don't have seccomp
+    if ((major < 3) || ((major == 3) && (minor < 8))) {
+        return false;
+    }
+
+    return true;
+}
+
 static JNINativeMethod gMethods[] = {
     {  "getNoNewPrivs", "()I",
             (void *) android_os_cts_OSFeatures_getNoNewPrivs  },
     {  "prctlCapBsetRead", "(I)I",
             (void *) android_os_cts_OSFeatures_prctlCapBsetRead },
     {  "hasSeccompSupport", "()Z",
-            (void *) android_os_cts_OSFeatures_hasSeccompSupport  }
+            (void *) android_os_cts_OSFeatures_hasSeccompSupport  },
+    {  "needsSeccompSupport", "()Z",
+            (void *) android_os_cts_OSFeatures_needsSeccompSupport  }
 };
 
 int register_android_os_cts_OSFeatures(JNIEnv* env)
diff --git a/tests/tests/os/res/raw/test1_new.obb b/tests/tests/os/res/raw/test1_new.obb
new file mode 100644
index 0000000..450af90
--- /dev/null
+++ b/tests/tests/os/res/raw/test1_new.obb
Binary files differ
diff --git a/tests/tests/os/res/xml/alias.xml b/tests/tests/os/res/xml/alias.xml
index 1166669..98fb5b2 100644
--- a/tests/tests/os/res/xml/alias.xml
+++ b/tests/tests/os/res/xml/alias.xml
@@ -19,7 +19,7 @@
 
 <alias xmlns:android="http://schemas.android.com/apk/res/android">
     <intent android:action="android.intent.action.MAIN"
-        android:targetPackage="com.android.cts.os"
+        android:targetPackage="android.os.cts"
         android:targetClass="android.os.cts.ChildActivity"
         android:data="http://www.google.com/">
     </intent>
diff --git a/tests/tests/os/src/android/os/cts/BuildTest.java b/tests/tests/os/src/android/os/cts/BuildTest.java
index 26b07f1..a0446bf 100644
--- a/tests/tests/os/src/android/os/cts/BuildTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildTest.java
@@ -38,15 +38,15 @@
 
     /** Tests that check the values of {@link Build#CPU_ABI} and {@link Build#CPU_ABI2}. */
     public void testCpuAbi() throws Exception {
-        testCpuAbiCommon();
+        runTestCpuAbiCommon();
         if (VMRuntime.getRuntime().is64Bit()) {
-            testCpuAbi64();
+            runTestCpuAbi64();
         } else {
-            testCpuAbi32();
+            runTestCpuAbi32();
         }
     }
 
-    private void testCpuAbiCommon() throws Exception {
+    private void runTestCpuAbiCommon() throws Exception {
         // The build property must match Build.SUPPORTED_ABIS exactly.
         final String[] abiListProperty = getStringList(RO_PRODUCT_CPU_ABILIST);
         assertEquals(Arrays.toString(abiListProperty), Arrays.toString(Build.SUPPORTED_ABIS));
@@ -75,7 +75,7 @@
         }
     }
 
-    private void testCpuAbi32() throws Exception {
+    private void runTestCpuAbi32() throws Exception {
         List<String> abi32 = Arrays.asList(Build.SUPPORTED_32_BIT_ABIS);
         assertTrue(abi32.contains(Build.CPU_ABI));
 
@@ -84,7 +84,7 @@
         }
     }
 
-    private void testCpuAbi64() {
+    private void runTestCpuAbi64() {
         List<String> abi64 = Arrays.asList(Build.SUPPORTED_64_BIT_ABIS);
         assertTrue(abi64.contains(Build.CPU_ABI));
 
diff --git a/tests/tests/os/src/android/os/cts/OSFeatures.java b/tests/tests/os/src/android/os/cts/OSFeatures.java
index 7c1eb82..9c4660c 100644
--- a/tests/tests/os/src/android/os/cts/OSFeatures.java
+++ b/tests/tests/os/src/android/os/cts/OSFeatures.java
@@ -24,4 +24,5 @@
     public static native int getNoNewPrivs();
     public static native int prctlCapBsetRead(int i);
     public static native boolean hasSeccompSupport();
+    public static native boolean needsSeccompSupport();
 }
diff --git a/tests/tests/os/src/android/os/cts/ParcelFileDescriptorProcessTest.java b/tests/tests/os/src/android/os/cts/ParcelFileDescriptorProcessTest.java
index 679a35c..a6a6b99 100644
--- a/tests/tests/os/src/android/os/cts/ParcelFileDescriptorProcessTest.java
+++ b/tests/tests/os/src/android/os/cts/ParcelFileDescriptorProcessTest.java
@@ -89,10 +89,10 @@
         // Bring up both remote processes and wire them to each other
         redIntent = new Intent();
         redIntent.setComponent(new ComponentName(
-                "com.android.cts.os", "android.os.cts.ParcelFileDescriptorPeer$Red"));
+                "android.os.cts", "android.os.cts.ParcelFileDescriptorPeer$Red"));
         blueIntent = new Intent();
         blueIntent.setComponent(new ComponentName(
-                "com.android.cts.os", "android.os.cts.ParcelFileDescriptorPeer$Blue"));
+                "android.os.cts", "android.os.cts.ParcelFileDescriptorPeer$Blue"));
         redConn = new PeerConnection();
         blueConn = new PeerConnection();
         context.startService(redIntent);
diff --git a/tests/tests/os/src/android/os/cts/SeccompTest.java b/tests/tests/os/src/android/os/cts/SeccompTest.java
index 410d004..7376079 100644
--- a/tests/tests/os/src/android/os/cts/SeccompTest.java
+++ b/tests/tests/os/src/android/os/cts/SeccompTest.java
@@ -60,12 +60,17 @@
     }
 
     public void testSeccomp() {
-        assertTrue("Please enable seccomp support "
-                   + "in your kernel (CONFIG_SECCOMP_FILTER=y)",
-                   OSFeatures.hasSeccompSupport());
+        if (OSFeatures.needsSeccompSupport()) {
+            assertTrue("Please enable seccomp support "
+                       + "in your kernel (CONFIG_SECCOMP_FILTER=y)",
+                       OSFeatures.hasSeccompSupport());
+        }
     }
 
     public void testKernelBasicTests() {
+        if (!OSFeatures.needsSeccompSupport())
+            return;
+
         if (isRunningUnderEmulatedAbi()) {
             Log.d(TAG, "Skipping test running under an emulated ABI");
             return;
@@ -97,6 +102,9 @@
     }
 
     public void testKernelTrapTests() {
+        if (!OSFeatures.needsSeccompSupport())
+            return;
+
         final String[] tests = {
             "TRAP.dfl",
             "TRAP.ign",
@@ -106,6 +114,9 @@
     }
 
     public void testKernelPrecedenceTests() {
+        if (!OSFeatures.needsSeccompSupport())
+            return;
+
         final String[] tests = {
             "precedence.allow_ok",
             "precedence.kill_is_highest",
@@ -122,6 +133,9 @@
 
     /* // The SECCOMP_RET_TRACE does not work under Android Arm32.
     public void testKernelTraceTests() {
+        if (!OSFeatures.needsSeccompSupport())
+            return;
+
         final String[] tests = {
             "TRACE_poke.read_has_side_effects",
             "TRACE_poke.getpid_runs_normally",
@@ -134,6 +148,9 @@
     */
 
     public void testKernelTSYNCTests() {
+        if (!OSFeatures.needsSeccompSupport())
+            return;
+
         if (isRunningUnderEmulatedAbi()) {
             Log.d(TAG, "Skipping test running under an emulated ABI");
             return;
@@ -174,6 +191,9 @@
      */
     public void testIsolatedServicePolicy() throws InterruptedException, ExecutionException,
            RemoteException {
+        if (!OSFeatures.needsSeccompSupport())
+            return;
+
         if (isRunningUnderEmulatedAbi()) {
             Log.d(TAG, "Skipping test running under an emulated ABI");
             return;
@@ -202,6 +222,9 @@
      */
     public void testViolateIsolatedServicePolicy() throws InterruptedException,
            ExecutionException, RemoteException {
+        if (!OSFeatures.needsSeccompSupport())
+            return;
+
         if (isRunningUnderEmulatedAbi()) {
             Log.d(TAG, "Skipping test running under an emulated ABI");
             return;
diff --git a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
index 90473d7..355ef65 100644
--- a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
+++ b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
@@ -16,7 +16,7 @@
 
 package android.os.storage.cts;
 
-import com.android.cts.os.R;
+import android.os.cts.R;
 
 import android.content.Context;
 import android.content.res.Resources;
@@ -47,7 +47,7 @@
     private static final long WAIT_TIME_INCR = 5*1000;
 
     private static final String OBB_MOUNT_PREFIX = "/mnt/obb/";
-    private static final String TEST1_CONTENTS = "1\n";
+    private static final String TEST1_NEW_CONTENTS = "1\n";
 
     private StorageManager mStorageManager;
 
@@ -59,16 +59,16 @@
 
     public void testMountAndUnmountObbNormal() throws IOException {
         for (File target : getTargetFiles()) {
-            target = new File(target, "test1.obb");
+            target = new File(target, "test1_new.obb");
             Log.d(TAG, "Testing path " + target);
             doMountAndUnmountObbNormal(target);
         }
     }
 
     private void doMountAndUnmountObbNormal(File outFile) throws IOException {
-        final String canonPath = mountObb(R.raw.test1, outFile, OnObbStateChangeListener.MOUNTED);
+        final String canonPath = mountObb(R.raw.test1_new, outFile, OnObbStateChangeListener.MOUNTED);
 
-        mountObb(R.raw.test1, outFile, OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
+        mountObb(R.raw.test1_new, outFile, OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
 
         try {
             final String mountPath = checkMountedPath(canonPath);
@@ -77,7 +77,7 @@
 
             assertTrue("OBB mounted path should be a directory", mountDir.isDirectory());
             assertTrue("test1.txt does not exist in OBB dir", testFile.exists());
-            assertFileContains(testFile, TEST1_CONTENTS);
+            assertFileContains(testFile, TEST1_NEW_CONTENTS);
         } finally {
             unmountObb(outFile, OnObbStateChangeListener.UNMOUNTED);
         }
@@ -130,8 +130,8 @@
     }
 
     private void doMountAndUnmountTwoObbs(File file1, File file2) throws IOException {
-        ObbObserver oo1 = mountObbWithoutWait(R.raw.test1, file1);
-        ObbObserver oo2 = mountObbWithoutWait(R.raw.test1, file2);
+        ObbObserver oo1 = mountObbWithoutWait(R.raw.test1_new, file1);
+        ObbObserver oo2 = mountObbWithoutWait(R.raw.test1_new, file2);
 
         Log.d(TAG, "Waiting for OBB #1 to complete mount");
         waitForObbActionCompletion(file1, oo1, OnObbStateChangeListener.MOUNTED);
@@ -144,14 +144,14 @@
             final File testFile1 = new File(mountDir1, "test1.txt");
             assertTrue("OBB mounted path should be a directory", mountDir1.isDirectory());
             assertTrue("test1.txt does not exist in OBB dir", testFile1.exists());
-            assertFileContains(testFile1, TEST1_CONTENTS);
+            assertFileContains(testFile1, TEST1_NEW_CONTENTS);
 
             final String mountPath2 = checkMountedPath(oo2.getPath());
             final File mountDir2 = new File(mountPath2);
             final File testFile2 = new File(mountDir2, "test1.txt");
             assertTrue("OBB mounted path should be a directory", mountDir2.isDirectory());
             assertTrue("test1.txt does not exist in OBB dir", testFile2.exists());
-            assertFileContains(testFile2, TEST1_CONTENTS);
+            assertFileContains(testFile2, TEST1_NEW_CONTENTS);
         } finally {
             unmountObb(file1, OnObbStateChangeListener.UNMOUNTED);
             unmountObb(file2, OnObbStateChangeListener.UNMOUNTED);
@@ -308,7 +308,7 @@
     private void unmountObb(final File file, int expectedState) {
         final ObbObserver observer = new ObbObserver();
 
-        assertTrue("unmountObb call on test1.obb should succeed",
+        assertTrue("unmountObb call on test1_new.obb should succeed",
                 mStorageManager.unmountObb(file.getPath(), false, observer));
 
         assertTrue("Unmount should have completed",
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index bc7119c..9024092 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -87,6 +87,7 @@
     <protected-broadcast android:name="android.os.action.DEVICE_IDLE_MODE_CHANGED" />
     <protected-broadcast android:name="android.os.action.POWER_SAVE_WHITELIST_CHANGED" />
     <protected-broadcast android:name="android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED" />
+    <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED_INTERNAL" />
 
     <protected-broadcast android:name="android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED" />
 
@@ -265,6 +266,7 @@
     <protected-broadcast android:name="com.android.server.WifiManager.action.START_SCAN" />
     <protected-broadcast android:name="com.android.server.WifiManager.action.START_PNO" />
     <protected-broadcast android:name="com.android.server.WifiManager.action.DELAYED_DRIVER_STOP" />
+    <protected-broadcast android:name="com.android.server.WifiManager.action.DEVICE_IDLE" />
     <protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_ACCEPTED" />
     <protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_DECLINED" />
     <protected-broadcast android:name="android.net.wifi.WIFI_STATE_CHANGED" />
@@ -374,7 +376,10 @@
     <protected-broadcast android:name="android.app.action.ACTION_PASSWORD_FAILED" />
     <protected-broadcast android:name="android.app.action.ACTION_PASSWORD_SUCCEEDED" />
     <protected-broadcast android:name="com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION" />
+
     <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_ADDED" />
+    <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNLOCKED" />
+    <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_REMOVED" />
 
     <protected-broadcast android:name="android.bluetooth.adapter.action.BLE_STATE_CHANGED" />
     <protected-broadcast android:name="android.content.jobscheduler.JOB_DELAY_EXPIRED" />
@@ -412,6 +417,7 @@
     <protected-broadcast android:name="android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED" />
     <protected-broadcast android:name="android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED" />
     <protected-broadcast android:name="android.os.storage.action.VOLUME_STATE_CHANGED" />
+    <protected-broadcast android:name="android.os.storage.action.DISK_SCANNED" />
     <protected-broadcast android:name="com.android.server.action.UPDATE_TWILIGHT_STATE" />
     <protected-broadcast android:name="com.android.server.device_idle.STEP_IDLE_STATE" />
     <protected-broadcast android:name="com.android.server.device_idle.STEP_LIGHT_IDLE_STATE" />
@@ -432,7 +438,6 @@
     <protected-broadcast android:name="android.intent.action.DYNAMIC_SENSOR_CHANGED" />
 
     <protected-broadcast android:name="android.intent.action.ACTION_RADIO_OFF" />
-    <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNLOCKED" />
 
     <protected-broadcast android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" />
     <protected-broadcast android:name="com.android.sync.SYNC_CONN_STATUS_CHANGED" />
@@ -450,6 +455,13 @@
 
     <protected-broadcast android:name="android.intent.action.TWILIGHT_CHANGED" />
 
+    <protected-broadcast android:name="com.android.server.fingerprint.ACTION_LOCKOUT_RESET" />
+    <protected-broadcast android:name="android.net.wifi.PASSPOINT_ICON_RECEIVED" />
+    <protected-broadcast android:name="com.android.server.notification.CountdownConditionProvider" />
+
+    <!-- @hide UCE service Notification -->
+    <protected-broadcast android:name="com.android.ims.internal.uce.UCE_SERVICE_UP" />
+
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
     <!-- ====================================================================== -->
@@ -694,7 +706,9 @@
                       android:description="@string/permgroupdesc_phone"
                       android:priority="500" />
 
-    <!-- Allows read only access to phone state.
+    <!-- Allows read only access to phone state, including the phone number of the device,
+         current cellular network information, the status of any ongoing calls, and a list of any
+         {@link android.telecom.PhoneAccount}s registered on the device.
          <p class="note"><strong>Note:</strong> If <em>both</em> your <a
          href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
          minSdkVersion}</a> and <a
@@ -823,6 +837,26 @@
                 android:protectionLevel="dangerous"/>
 
     <!-- ====================================================================== -->
+    <!-- Permissions for accessing the UCE Service                              -->
+    <!-- ====================================================================== -->
+
+    <!-- @hide Allows an application to Access UCE-Presence.
+         <p>Protection level: dangerous
+    -->
+    <permission android:name="android.permission.ACCESS_UCE_PRESENCE_SERVICE"
+                android:permissionGroup="android.permission-group.PHONE"
+                android:protectionLevel="dangerous"/>
+
+    <!-- @hide Allows an application to Access UCE-OPTIONS.
+         <p>Protection level: dangerous
+    -->
+    <permission android:name="android.permission.ACCESS_UCE_OPTIONS_SERVICE"
+                android:permissionGroup="android.permission-group.PHONE"
+                android:protectionLevel="dangerous"/>
+
+
+
+    <!-- ====================================================================== -->
     <!-- Permissions for accessing the device camera                            -->
     <!-- ====================================================================== -->
     <eat-comment />
@@ -965,16 +999,6 @@
     <!-- INSTALL PERMISSIONS                                                    -->
     <!-- ====================================================================== -->
 
-    `   <!-- =========================================== -->
-    <!-- Permissions for accessing contact metadata -->
-    <!-- =========================================== -->
-    <eat-comment />
-
-    <!-- @SystemApi Allows an application to read/write contact metadata.
-         <p>Not for use by third-party applications. -->
-    <permission android:name="android.permission.READ_WRITE_CONTACT_METADATA"
-                android:protectionLevel="signature|system" />
-
     <!-- ================================== -->
     <!-- Permissions for accessing messages -->
     <!-- ================================== -->
@@ -986,6 +1010,11 @@
     <permission android:name="android.permission.SEND_RESPOND_VIA_MESSAGE"
                 android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows an application to send SMS to premium shortcodes without user permission.
+         <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.SEND_SMS_NO_CONFIRMATION"
+                android:protectionLevel="signature|privileged" />
+
     <!-- Allows an application to filter carrier specific sms.
          @hide -->
     <permission android:name="android.permission.CARRIER_FILTER_SMS"
@@ -1255,7 +1284,7 @@
     <!-- ================================== -->
     <eat-comment />
 
-    <!-- Allows applications to enter Wi-Fi Multicast mode.
+    <!-- Allows applications to enter Wi-Fi ffMulticast mode.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"
@@ -1480,11 +1509,21 @@
 
     <!-- Allows an application to manage access to documents, usually as part
          of a document picker.
+         <p>This permission should <em>only</em> be requested by the platform
+         document management app.  This permission cannot be granted to
+         third-party apps.
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.MANAGE_DOCUMENTS"
                 android:protectionLevel="signature" />
 
+    <!-- @hide Allows an application to cache content.
+         <p>Not for use by third-party applications.
+         <p>Protection level: signature
+    -->
+    <permission android:name="android.permission.CACHE_CONTENT"
+                android:protectionLevel="signature" />
+
     <!-- ================================== -->
     <!-- Permissions for screenlock         -->
     <!-- ================================== -->
@@ -1608,6 +1647,11 @@
     <permission android:name="android.permission.GET_PACKAGE_IMPORTANCE"
                 android:protectionLevel="signature|privileged" />
 
+    <!-- Allows use of PendingIntent.getIntent().
+         @hide -->
+    <permission android:name="android.permission.GET_INTENT_SENDER_INTENT"
+                android:protectionLevel="signature" />
+
     <!-- ================================== -->
     <!-- Permissions affecting the display of other applications  -->
     <!-- ================================== -->
@@ -2128,6 +2172,15 @@
     <permission android:name="android.permission.BIND_PRINT_SERVICE"
                 android:protectionLevel="signature" />
 
+    <!-- Must be required by a {@link android.printservice.recommendation.RecommendationService},
+     to ensure that only the system can bind to it.
+     @hide
+     @SystemApi
+     <p>Protection level: signature
+    -->
+    <permission android:name="android.permission.BIND_PRINT_RECOMMENDATION_SERVICE"
+                android:protectionLevel="signature" />
+
     <!-- Must be required by a {@link android.nfc.cardemulation.HostApduService}
          or {@link android.nfc.cardemulation.OffHostApduService} to ensure that only
          the system can bind to it.
@@ -2695,7 +2748,7 @@
          OTA reboot *not* occur while the lock is held.
          @hide -->
     <permission android:name="android.permission.UPDATE_LOCK"
-                android:protectionLevel="signature|privileged" />
+                android:protectionLevel="signature|fvprivileged" />
 
     <!-- @SystemApi Allows an application to read the current set of notifications, including
          any metadata and intents attached.
@@ -2766,12 +2819,11 @@
                 android:protectionLevel="signature" />
 
     <!-- Must be required by an {@link
-         android.service.notification.NotificationAssistantService},
-         to ensure that only the system can bind to it.
+         android.service.notification.NotificationRankerService         to ensure that only the system can bind to it.
          <p>Protection level: signature
          @hide This is not a third-party API (intended for system apps). -->
     -->
-    <permission android:name="android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE"
+    <permission android:name="android.permission.BIND_NOTIFICATION_RANKER_SERVICE"
                 android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link
@@ -2926,6 +2978,12 @@
     <permission android:name="android.permission.WRITE_BLOCKED_NUMBERS"
                 android:protectionLevel="signature" />
 
+    <!-- Must be required by an {@link android.service.vr.VrListenerService}, to ensure that only
+         the system can bind to it.
+         <p>Protection level: signature -->
+    <permission android:name="android.permission.BIND_VR_LISTENER_SERVICE"
+                android:protectionLevel="signature" />
+
     <application android:process="system"
                  android:persistent="true"
                  android:hasCode="false"
@@ -2935,9 +2993,9 @@
                  android:killAfterRestore="false"
                  android:icon="@drawable/ic_launcher_android"
                  android:supportsRtl="true"
-                 android:theme="@style/Theme.Material.DayNight.DarkActionBar"
-                 android:forceDeviceEncrypted="true"
-                 android:encryptionAware="true">
+                 android:theme="@style/Theme.Material.Light.DarkActionBar"
+                 android:defaultToDeviceProtectedStorage="true"
+                 android:directBootAware="true">
         <activity android:name="com.android.internal.app.ChooserActivity"
                   android:theme="@style/Theme.DeviceDefault.Resolver"
                   android:finishOnCloseSystemDialogs="true"
@@ -2971,7 +3029,7 @@
                         android:label="@string/managed_profile_label">
         </activity-alias>
         <activity android:name="com.android.internal.app.HeavyWeightSwitcherActivity"
-                  android:theme="@style/Theme.Material.DayNight.Dialog"
+                  android:theme="@style/Theme.Material.Light.Dialog"
                   android:label="@string/heavy_weight_switcher_title"
                   android:finishOnCloseSystemDialogs="true"
                   android:excludeFromRecents="true"
@@ -3004,7 +3062,7 @@
         <activity android:name="android.accounts.ChooseAccountActivity"
                   android:excludeFromRecents="true"
                   android:exported="true"
-                  android:theme="@style/Theme.Material.DayNight.Dialog"
+                  android:theme="@style/Theme.Material.Light.Dialog"
                   android:label="@string/choose_account_label"
                   android:process=":ui">
         </activity>
@@ -3012,14 +3070,14 @@
         <activity android:name="android.accounts.ChooseTypeAndAccountActivity"
                   android:excludeFromRecents="true"
                   android:exported="true"
-                  android:theme="@style/Theme.Material.DayNight.Dialog"
+                  android:theme="@style/Theme.Material.Light.Dialog"
                   android:label="@string/choose_account_label"
                   android:process=":ui">
         </activity>
 
         <activity android:name="android.accounts.ChooseAccountTypeActivity"
                   android:excludeFromRecents="true"
-                  android:theme="@style/Theme.Material.DayNight.Dialog"
+                  android:theme="@style/Theme.Material.Light.Dialog"
                   android:label="@string/choose_account_label"
                   android:process=":ui">
         </activity>
@@ -3027,19 +3085,19 @@
         <activity android:name="android.accounts.CantAddAccountActivity"
                   android:excludeFromRecents="true"
                   android:exported="true"
-                  android:theme="@style/Theme.Material.DayNight.Dialog.NoActionBar"
+                  android:theme="@style/Theme.Material.Light.Dialog.NoActionBar"
                   android:process=":ui">
         </activity>
 
         <activity android:name="android.accounts.GrantCredentialsPermissionActivity"
                   android:excludeFromRecents="true"
                   android:exported="true"
-                  android:theme="@style/Theme.Material.DayNight.DialogWhenLarge"
+                  android:theme="@style/Theme.Material.Light.DialogWhenLarge"
                   android:process=":ui">
         </activity>
 
         <activity android:name="android.content.SyncActivityTooManyDeletes"
-                  android:theme="@style/Theme.Material.DayNight.Dialog"
+                  android:theme="@style/Theme.Material.Light.Dialog"
                   android:label="@string/sync_too_many_deletes"
                   android:process=":ui">
         </activity>
@@ -3059,7 +3117,7 @@
         </activity>
 
         <activity android:name="com.android.internal.app.NetInitiatedActivity"
-                  android:theme="@style/Theme.Material.DayNight.Dialog.Alert"
+                  android:theme="@style/Theme.Material.Light.Dialog.Alert"
                   android:excludeFromRecents="true"
                   android:process=":ui">
         </activity>
@@ -3080,7 +3138,7 @@
         <activity android:name="com.android.internal.app.ConfirmUserCreationActivity"
                   android:excludeFromRecents="true"
                   android:process=":ui"
-                  android:theme="@style/Theme.Material.DayNight.Dialog.Alert">
+                  android:theme="@style/Theme.Material.Light.Dialog.Alert">
             <intent-filter android:priority="1000">
                 <action android:name="android.os.action.CREATE_USER" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -3088,7 +3146,7 @@
         </activity>
 
         <activity android:name="com.android.internal.app.UnlaunchableAppActivity"
-                  android:theme="@style/Theme.Material.DayNight.Dialog.Alert"
+                  android:theme="@style/Theme.Material.Light.Dialog.Alert"
                   android:excludeFromRecents="true"
                   android:process=":ui">
         </activity>
diff --git a/tests/tests/print/src/android/print/cts/BasePrintTest.java b/tests/tests/print/src/android/print/cts/BasePrintTest.java
index 44f9ff1..7a31e5f 100644
--- a/tests/tests/print/src/android/print/cts/BasePrintTest.java
+++ b/tests/tests/print/src/android/print/cts/BasePrintTest.java
@@ -105,6 +105,7 @@
     private CallCounter mWriteCallCounter;
     private CallCounter mFinishCallCounter;
     private CallCounter mPrintJobQueuedCallCounter;
+    private CallCounter mCreateSessionCallCounter;
     private CallCounter mDestroySessionCallCounter;
 
     private String[] mEnabledImes;
@@ -189,6 +190,7 @@
         mWriteCallCounter = new CallCounter();
         mFinishCallCounter = new CallCounter();
         mPrintJobQueuedCallCounter = new CallCounter();
+        mCreateSessionCallCounter = new CallCounter();
         mDestroySessionCallCounter = new CallCounter();
 
         // Create the activity for the right locale.
@@ -261,6 +263,10 @@
         mPrintJobQueuedCallCounter.call();
     }
 
+    protected void onPrinterDiscoverySessionCreateCalled() {
+        mCreateSessionCallCounter.call();
+    }
+
     protected void onPrinterDiscoverySessionDestroyCalled() {
         mDestroySessionCallCounter.call();
     }
@@ -270,6 +276,11 @@
                 "Did not get expected call to onCancel for the current operation.");
     }
 
+    protected void waitForPrinterDiscoverySessionCreateCallbackCalled() {
+        waitForCallbackCallCount(mCreateSessionCallCounter, 1,
+                "Did not get expected call to onCreatePrinterDiscoverySession.");
+    }
+
     protected void waitForPrinterDiscoverySessionDestroyCallbackCalled() {
         waitForCallbackCallCount(mDestroySessionCallCounter, 1,
                 "Did not get expected call to onDestroyPrinterDiscoverySession.");
diff --git a/tests/tests/print/src/android/print/cts/ClassParametersTest.java b/tests/tests/print/src/android/print/cts/ClassParametersTest.java
new file mode 100644
index 0000000..bad47f8
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/ClassParametersTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.cts;
+
+import android.print.PrintAttributes;
+import android.print.PrintAttributes.MediaSize;
+import android.print.PrintAttributes.Resolution;
+import android.print.PrintDocumentInfo;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test that the print attributes are correctly propagated through the print framework
+ */
+@RunWith(AndroidJUnit4.class)
+public class ClassParametersTest {
+    /**
+     * Run a runnable and expect and exception of a certain type.
+     *
+     * @param r The runnable to run
+     * @param expectedClass The expected exception type
+     */
+    private void assertException(Runnable r, Class<? extends RuntimeException> expectedClass) {
+        try {
+            r.run();
+        } catch (Exception e) {
+            if (e.getClass().isAssignableFrom(expectedClass)) {
+                return;
+            } else {
+                throw new AssertionError("Expected: " + expectedClass.getName() + ", got: "
+                        + e.getClass().getName());
+            }
+        }
+
+        throw new AssertionError("No exception thrown");
+    }
+
+    /**
+     * Test that we cannot create PrintAttributes with illegal parameters.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    @Test
+    public void testIllegalPrintAttributes() throws Exception {
+        assertException(() -> (new PrintAttributes.Builder()).setColorMode(-1),
+                IllegalArgumentException.class);
+        assertException(() -> (new PrintAttributes.Builder()).setColorMode(0),
+                IllegalArgumentException.class);
+        assertException(() -> (new PrintAttributes.Builder()).setColorMode(
+                PrintAttributes.COLOR_MODE_COLOR | PrintAttributes.COLOR_MODE_MONOCHROME),
+                IllegalArgumentException.class);
+
+        assertException(() -> (new PrintAttributes.Builder()).setDuplexMode(-1),
+                IllegalArgumentException.class);
+        assertException(() -> (new PrintAttributes.Builder()).setDuplexMode(0),
+                IllegalArgumentException.class);
+        assertException(() -> (new PrintAttributes.Builder()).setDuplexMode(
+                PrintAttributes.DUPLEX_MODE_LONG_EDGE | PrintAttributes.DUPLEX_MODE_NONE),
+                IllegalArgumentException.class);
+
+        assertException(() -> new Resolution(null, "label", 10, 10),
+                IllegalArgumentException.class);
+        assertException(() -> new Resolution("", "label", 10, 10),
+                IllegalArgumentException.class);
+        assertException(() -> new Resolution("id", null, 10, 10),
+                IllegalArgumentException.class);
+        assertException(() -> new Resolution("id", "", 10, 10),
+                IllegalArgumentException.class);
+        assertException(() -> new Resolution("id", "label", -10, 10),
+                IllegalArgumentException.class);
+        assertException(() -> new Resolution("id", "label", 0, 10),
+                IllegalArgumentException.class);
+        assertException(() -> new Resolution("id", "label", 10, -10),
+                IllegalArgumentException.class);
+        assertException(() -> new Resolution("id", "label", 10, 0),
+                IllegalArgumentException.class);
+
+        assertException(() -> new MediaSize(null, "label", 10, 10),
+                IllegalArgumentException.class);
+        assertException(() -> new MediaSize("", "label", 10, 10),
+                IllegalArgumentException.class);
+        assertException(() -> new MediaSize("id", null, 10, 10),
+                IllegalArgumentException.class);
+        assertException(() -> new MediaSize("id", "", 10, 10),
+                IllegalArgumentException.class);
+        assertException(() -> new MediaSize("id", "label", -10, 10),
+                IllegalArgumentException.class);
+        assertException(() -> new MediaSize("id", "label", 0, 10),
+                IllegalArgumentException.class);
+        assertException(() -> new MediaSize("id", "label", 10, -10),
+                IllegalArgumentException.class);
+        assertException(() -> new MediaSize("id", "label", 10, 0),
+                IllegalArgumentException.class);
+
+        // There is no restrictions on what parameters to set for minMargins.
+    }
+
+    /**
+     * Test that we cannot create PrintDocumentInfo with illegal parameters.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    @Test
+    public void testIllegalPrintDocumentInfo() throws Exception {
+        assertException(() -> new PrintDocumentInfo.Builder(null),
+                IllegalArgumentException.class);
+        assertException(() -> new PrintDocumentInfo.Builder(""),
+                IllegalArgumentException.class);
+
+        assertException(() -> new PrintDocumentInfo.Builder("doc").setPageCount(-2),
+                IllegalArgumentException.class);
+        // -1 == UNKNOWN and 0 are allowed
+
+        // Content type is not restricted
+    }
+}
diff --git a/tests/tests/print/src/android/print/cts/PrintAttributesTest.java b/tests/tests/print/src/android/print/cts/PrintAttributesTest.java
index 855f587..1b8c318 100644
--- a/tests/tests/print/src/android/print/cts/PrintAttributesTest.java
+++ b/tests/tests/print/src/android/print/cts/PrintAttributesTest.java
@@ -637,7 +637,7 @@
      *
      * @throws Exception If anything is unexpected
      */
-    public void testIllegalSuggested() throws Exception {
+    public void testUnsupportedSuggested() throws Exception {
         //       available                               default          suggestion
         baseTest(                                        MIN_MARGINS[0],
                  Arrays.copyOfRange(MEDIA_SIZES, 0, 1),  MEDIA_SIZES[0],  MEDIA_SIZES[1],
@@ -645,4 +645,19 @@
                  Arrays.copyOfRange(DUPLEX_MODES, 0, 1), DUPLEX_MODES[0], DUPLEX_MODES[1],
                  Arrays.copyOfRange(RESOLUTIONS, 0, 1),  RESOLUTIONS[0],  RESOLUTIONS[1]);
     }
+
+    /**
+     * Test that negative Margins do not cause issues in the print print spooler. Negative margins
+     * are allowed because of historical reasons.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    public void testNegativeMargins() throws Exception {
+        //       available     default                          suggestion
+        baseTest(              new Margins(-10, -10, -10, -10),
+                 MEDIA_SIZES,  MEDIA_SIZES[1],                  null,
+                 COLOR_MODES,  COLOR_MODES[1],                  0,
+                 DUPLEX_MODES, DUPLEX_MODES[1],                 0,
+                 RESOLUTIONS,  RESOLUTIONS[1],                  null);
+    }
 }
diff --git a/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java b/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
index 7d0157b..b539a83 100644
--- a/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
+++ b/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
@@ -1665,6 +1665,154 @@
         waitForPrinterDiscoverySessionDestroyCallbackCalled();
     }
 
+    /**
+     * Executes a print process with a given print document info
+     *
+     * @param info The print document info to declare on layout
+     */
+    private void printDocumentInfoBaseTest(final PrintDocumentInfo info) throws Exception {
+        if (!supportsPrinting()) {
+            return;
+        }
+        // Configure the print services.
+        FirstPrintService.setCallbacks(createFirstMockPrintServiceCallbacks());
+        SecondPrintService.setCallbacks(createSecondMockPrintServiceCallbacks());
+
+        final PrintAttributes[] printAttributes = new PrintAttributes[1];
+
+        // Create a mock print adapter.
+        final PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+                new Answer<Void>() {
+                    @Override
+                    public Void answer(InvocationOnMock invocation) throws Throwable {
+                        printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+                        LayoutResultCallback callback = (LayoutResultCallback) invocation.getArguments()[3];
+                        callback.onLayoutFinished(info, false);
+                        // Mark layout was called.
+                        onLayoutCalled();
+                        return null;
+                    }
+                }, new Answer<Void>() {
+                    @Override
+                    public Void answer(InvocationOnMock invocation) throws Throwable {
+                        Object[] args = invocation.getArguments();
+                        PageRange[] pages = (PageRange[]) args[0];
+                        ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                        WriteResultCallback callback = (WriteResultCallback) args[3];
+                        writeBlankPages(printAttributes[0], fd, 0, 1);
+                        fd.close();
+                        callback.onWriteFinished(pages);
+                        // Mark write was called.
+                        onWriteCalled();
+                        return null;
+                    }
+                }, new Answer<Void>() {
+                    @Override
+                    public Void answer(InvocationOnMock invocation) throws Throwable {
+                        // Mark finish was called.
+                        onFinishCalled();
+                        return null;
+                    }
+                });
+
+        // Start printing.
+        print(adapter);
+
+        // Select the second printer.
+        selectPrinter("Second printer");
+
+        // Wait for layout.
+        waitForLayoutAdapterCallbackCount(2);
+
+        // Click the print button.
+        clickPrintButton();
+
+        // Answer the dialog for the print service cloud warning
+        answerPrintServicesWarning(true);
+
+        // Wait for the session to be destroyed to isolate tests.
+        waitForPrinterDiscoverySessionDestroyCallbackCalled();
+    }
+
+    /**
+     * Test that the default values of the PrintDocumentInfo are fine.
+     *
+     * @throws Exception If anything unexpected happens
+     */
+    public void testDocumentInfoNothingSet() throws Exception {
+        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME)).build());
+    }
+
+    /**
+     * Test that a unknown page count is handled correctly.
+     *
+     * @throws Exception If anything unexpected happens
+     */
+    public void testDocumentInfoUnknownPageCount() throws Exception {
+        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
+                .setPageCount(PrintDocumentInfo.PAGE_COUNT_UNKNOWN).build());
+    }
+
+    /**
+     * Test that zero page count is handled correctly.
+     *
+     * @throws Exception If anything unexpected happens
+     */
+    public void testDocumentInfoZeroPageCount() throws Exception {
+        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
+                .setPageCount(0).build());
+    }
+
+    /**
+     * Test that page count one is handled correctly. (The document has two pages)
+     *
+     * @throws Exception If anything unexpected happens
+     */
+    public void testDocumentInfoOnePageCount() throws Exception {
+        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
+                .setPageCount(1).build());
+    }
+
+    /**
+     * Test that page count three is handled correctly. (The document has two pages)
+     *
+     * @throws Exception If anything unexpected happens
+     */
+    public void testDocumentInfoThreePageCount() throws Exception {
+        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
+                .setPageCount(3).build());
+    }
+
+    /**
+     * Test that a photo content type is handled correctly.
+     *
+     * @throws Exception If anything unexpected happens
+     */
+    public void testDocumentInfoContentTypePhoto() throws Exception {
+        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
+                .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO).build());
+    }
+
+    /**
+     * Test that a unknown content type is handled correctly.
+     *
+     * @throws Exception If anything unexpected happens
+     */
+    public void testDocumentInfoContentTypeUnknown() throws Exception {
+        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
+                .setContentType(PrintDocumentInfo.CONTENT_TYPE_UNKNOWN).build());
+    }
+
+    /**
+     * Test that a undefined content type is handled correctly.
+     *
+     * @throws Exception If anything unexpected happens
+     */
+    public void testDocumentInfoContentTypeNonDefined() throws Exception {
+        printDocumentInfoBaseTest((new PrintDocumentInfo.Builder(PRINT_JOB_NAME))
+                .setContentType(-23).build());
+    }
+
     private PrintServiceCallbacks createFirstMockPrintServiceCallbacks() {
         final PrinterDiscoverySessionCallbacks callbacks =
                 createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
diff --git a/tests/tests/print/src/android/print/cts/PrinterCapabilitiesTest.java b/tests/tests/print/src/android/print/cts/PrinterCapabilitiesTest.java
index 2ed21b9..1df068d 100644
--- a/tests/tests/print/src/android/print/cts/PrinterCapabilitiesTest.java
+++ b/tests/tests/print/src/android/print/cts/PrinterCapabilitiesTest.java
@@ -43,6 +43,8 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeoutException;
+import java.util.function.Consumer;
+import java.util.function.Function;
 
 /**
  * This test verifies changes to the printer capabilities are applied correctly.
@@ -51,8 +53,14 @@
     private static final String LOG_TAG = "PrinterCapabilitiesTest";
     private static final String PRINTER_NAME = "Test printer";
 
+    private static final Margins DEFAULT_MARGINS = new Margins(0, 0, 0, 0);
+    private static final PrintAttributes.Resolution RESOLUTION_300 =
+            new PrintAttributes.Resolution("300", "300", 300, 300);
+    private static final PrintAttributes.Resolution RESOLUTION_600 =
+            new PrintAttributes.Resolution("600", "600", 600, 600);
+
     /**
-     * Generate a new list of printers containing a singler printer with the given media size and
+     * Generate a new list of printers containing a singer printer with the given media size and
      * status. The other capabilities are default values.
      *
      * @param printerId The id of the printer
@@ -70,13 +78,13 @@
         if (mediaSize != null) {
             PrinterCapabilitiesInfo.Builder builder = new PrinterCapabilitiesInfo.Builder(
                     printerId);
-            builder.setMinMargins(new Margins(0, 0, 0, 0))
+            builder.setMinMargins(DEFAULT_MARGINS)
                     .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
                             PrintAttributes.COLOR_MODE_COLOR)
                     .setDuplexModes(PrintAttributes.DUPLEX_MODE_NONE,
                             PrintAttributes.DUPLEX_MODE_NONE)
                     .addMediaSize(mediaSize, true)
-                    .addResolution(new Resolution("300x300", "300x300", 300, 300), true);
+                    .addResolution(RESOLUTION_300, true);
             cap = builder.build();
         } else {
             cap = null;
@@ -339,4 +347,409 @@
 
         waitForPrinterDiscoverySessionDestroyCallbackCalled();
     }
+
+    /**
+     * Run a runnable and expect and exception of a certain type.
+     *
+     * @param r The runnable to run
+     * @param expectedClass The expected exception type
+     */
+    private void assertException(Runnable r, Class<? extends RuntimeException> expectedClass) {
+        try {
+            r.run();
+        } catch (Exception e) {
+            if (e.getClass().isAssignableFrom(expectedClass)) {
+                return;
+            } else {
+                throw new AssertionError("Expected: " + expectedClass.getName() + ", got: "
+                        + e.getClass().getName());
+            }
+        }
+
+        throw new AssertionError("No exception thrown");
+    }
+
+    /**
+     * That that you cannot create illegal PrinterCapabilityInfos.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    public void testIllegalPrinterCapabilityInfos() throws Exception {
+        if (!supportsPrinting()) {
+            return;
+        }
+
+        final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
+                createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
+                    @Override
+                    public Void answer(InvocationOnMock invocation) {
+                        StubbablePrinterDiscoverySession session =
+                                ((PrinterDiscoverySessionCallbacks)
+                                        invocation.getMock()).getSession();
+
+                        PrinterId printerId = session.getService().generatePrinterId(PRINTER_NAME);
+
+                        // printerId need to be set
+                        assertException(() -> new PrinterCapabilitiesInfo.Builder(null),
+                                IllegalArgumentException.class);
+
+                        // All capability fields (beside duplex) need to be initialized:
+                        // Test no color
+                        assertException(() ->
+                                        (new PrinterCapabilitiesInfo.Builder(printerId))
+                                                .setMinMargins(DEFAULT_MARGINS)
+                                                .addMediaSize(MediaSize.ISO_A4, true)
+                                                .addResolution(RESOLUTION_300, true).build(),
+                                IllegalStateException.class);
+                        // Test bad colors
+                        assertException(() ->
+                                        (new PrinterCapabilitiesInfo.Builder(printerId))
+                                                .setColorModes(0xffff,
+                                                        PrintAttributes.COLOR_MODE_MONOCHROME),
+                                IllegalArgumentException.class);
+                        // Test bad duplex mode
+                        assertException(() ->
+                                        (new PrinterCapabilitiesInfo.Builder(printerId))
+                                                .setDuplexModes(0xffff,
+                                                        PrintAttributes.DUPLEX_MODE_NONE),
+                                IllegalArgumentException.class);
+                        // Test no mediasize
+                        assertException(() ->
+                                        (new PrinterCapabilitiesInfo.Builder(printerId))
+                                                .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+                                                        PrintAttributes.COLOR_MODE_COLOR)
+                                                .setMinMargins(DEFAULT_MARGINS)
+                                                .addResolution(RESOLUTION_300, true).build(),
+                                IllegalStateException.class);
+                        // Test no default mediasize
+                        assertException(() ->
+                                        (new PrinterCapabilitiesInfo.Builder(printerId))
+                                                .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+                                                        PrintAttributes.COLOR_MODE_COLOR)
+                                                .setMinMargins(DEFAULT_MARGINS)
+                                                .addMediaSize(MediaSize.ISO_A4, false)
+                                                .addResolution(RESOLUTION_300, true).build(),
+                                IllegalStateException.class);
+                        // Test two default mediasizes
+                        assertException(() ->
+                                        (new PrinterCapabilitiesInfo.Builder(printerId))
+                                                .addMediaSize(MediaSize.ISO_A4, true)
+                                                .addMediaSize(MediaSize.ISO_A5, true),
+                                IllegalArgumentException.class);
+                        // Test no resolution
+                        assertException(() ->
+                                        (new PrinterCapabilitiesInfo.Builder(printerId))
+                                                .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+                                                        PrintAttributes.COLOR_MODE_COLOR)
+                                                .setMinMargins(DEFAULT_MARGINS)
+                                                .addMediaSize(MediaSize.ISO_A4, true).build(),
+                                IllegalStateException.class);
+                        // Test no default resolution
+                        assertException(() ->
+                                        (new PrinterCapabilitiesInfo.Builder(printerId))
+                                                .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+                                                        PrintAttributes.COLOR_MODE_COLOR)
+                                                .setMinMargins(DEFAULT_MARGINS)
+                                                .addMediaSize(MediaSize.ISO_A4, true)
+                                                .addResolution(RESOLUTION_300, false).build(),
+                                IllegalStateException.class);
+                        // Test two default resolutions
+                        assertException(() ->
+                                        (new PrinterCapabilitiesInfo.Builder(printerId))
+                                                .addResolution(RESOLUTION_300, true)
+                                                .addResolution(RESOLUTION_600, true),
+                                IllegalArgumentException.class);
+
+                        onPrinterDiscoverySessionCreateCalled();
+                        return null;
+                    }
+                }, null, null, null, null, null, new Answer<Void>() {
+                    @Override
+                    public Void answer(InvocationOnMock invocation) {
+                        onPrinterDiscoverySessionDestroyCalled();
+                        return null;
+                    }
+                });
+
+        // Create the service callbacks for the first print service.
+        PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
+                new Answer<PrinterDiscoverySessionCallbacks>() {
+                    @Override
+                    public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+                        return firstSessionCallbacks;
+                    }
+                }, null, null);
+
+        // Configure the print services.
+        FirstPrintService.setCallbacks(firstServiceCallbacks);
+        SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
+
+        PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(null, null, null);
+
+        // Start printing.
+        print(adapter);
+
+        waitForPrinterDiscoverySessionCreateCallbackCalled();
+
+        getUiDevice().pressBack();
+
+        waitForPrinterDiscoverySessionDestroyCallbackCalled();
+    }
+
+    /**
+     * That that you can use all sane legal PrinterCapabilityInfos.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    public void testSanePrinterCapabilityInfos() throws Exception {
+        if (!supportsPrinting()) {
+            return;
+        }
+
+        final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
+                createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
+                    @Override
+                    public Void answer(InvocationOnMock invocation) {
+                        StubbablePrinterDiscoverySession session =
+                                ((PrinterDiscoverySessionCallbacks)
+                                        invocation.getMock()).getSession();
+
+                        MediaSize[] mediaSizes = {MediaSize.ISO_A0, MediaSize.ISO_A0,
+                                MediaSize.ISO_A1};
+                        Resolution[] resolutions = {RESOLUTION_300, RESOLUTION_300,
+                                RESOLUTION_600};
+                        int[] colorModes = {PrintAttributes.COLOR_MODE_MONOCHROME,
+                                PrintAttributes.COLOR_MODE_COLOR};
+                        int[] duplexModes = {PrintAttributes.DUPLEX_MODE_NONE,
+                                PrintAttributes.DUPLEX_MODE_LONG_EDGE,
+                                PrintAttributes.DUPLEX_MODE_SHORT_EDGE};
+
+                        ArrayList<PrinterInfo> printers = new ArrayList<>();
+                        for (int mediaSizeIndex = 1; mediaSizeIndex < mediaSizes.length;
+                             mediaSizeIndex++) {
+                            for (int resolutionIndex = 1; resolutionIndex < mediaSizes.length;
+                                 resolutionIndex++) {
+                                for (int colorIndex = 1; colorIndex < colorModes.length;
+                                     colorIndex++) {
+                                    for (int duplexIndex = 1; duplexIndex < duplexModes.length;
+                                         duplexIndex++) {
+                                        PrinterId printerId = session.getService()
+                                                .generatePrinterId(Integer.valueOf(printers.size())
+                                                        .toString());
+
+                                        PrinterCapabilitiesInfo.Builder b =
+                                                new PrinterCapabilitiesInfo.Builder(printerId);
+
+                                        for (int i = 0; i < mediaSizeIndex; i++) {
+                                            b.addMediaSize(mediaSizes[i], i == mediaSizeIndex - 1);
+                                        }
+
+                                        for (int i = 0; i < resolutionIndex; i++) {
+                                            b.addResolution(resolutions[i],
+                                                    i == resolutionIndex - 1);
+                                        }
+
+                                        int allColors = 0;
+                                        for (int i = 0; i < colorIndex; i++) {
+                                            allColors |= colorModes[i];
+                                        }
+                                        b.setColorModes(allColors, colorModes[colorIndex - 1]);
+
+                                        int allDuplexModes = 0;
+                                        for (int i = 0; i < duplexIndex; i++) {
+                                            allDuplexModes |= duplexModes[i];
+                                        }
+                                        b.setDuplexModes(allDuplexModes,
+                                                duplexModes[duplexIndex - 1]);
+
+                                        printers.add((new PrinterInfo.Builder(printerId,
+                                                Integer.valueOf(printers.size()).toString(),
+                                                PrinterInfo.STATUS_IDLE)).setCapabilities(b.build())
+                                                .build());
+                                    }
+                                }
+                            }
+                        }
+
+                        session.addPrinters(printers);
+
+                        onPrinterDiscoverySessionCreateCalled();
+                        return null;
+                    }
+                }, null, null, null, null, null, new Answer<Void>() {
+                    @Override
+                    public Void answer(InvocationOnMock invocation) {
+                        onPrinterDiscoverySessionDestroyCalled();
+                        return null;
+                    }
+                });
+
+        // Create the service callbacks for the first print service.
+        PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
+                new Answer<PrinterDiscoverySessionCallbacks>() {
+                    @Override
+                    public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+                        return firstSessionCallbacks;
+                    }
+                }, null, null);
+
+        // Configure the print services.
+        FirstPrintService.setCallbacks(firstServiceCallbacks);
+        SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
+
+        PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(null, null, null);
+
+        // Start printing.
+        print(adapter);
+
+        waitForPrinterDiscoverySessionCreateCallbackCalled();
+
+        getUiDevice().pressBack();
+
+        waitForPrinterDiscoverySessionDestroyCallbackCalled();
+    }
+
+    /**
+     * Base test that performs a print operation with a give PrinterCapabilityInfo and run a test
+     * function before finishing.
+     *
+     * @throws Exception
+     */
+    private void testPrinterCapabilityInfo(final Function<PrinterId, PrinterCapabilitiesInfo>
+            capBuilder, Consumer<PrintAttributes> test) throws Exception {
+        if (!supportsPrinting()) {
+            return;
+        }
+
+        final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
+                createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
+                    @Override
+                    public Void answer(InvocationOnMock invocation) {
+                        StubbablePrinterDiscoverySession session =
+                                ((PrinterDiscoverySessionCallbacks)
+                                        invocation.getMock()).getSession();
+
+                        PrinterId printerId = session.getService()
+                                .generatePrinterId(PRINTER_NAME);
+
+                        ArrayList<PrinterInfo> printers = new ArrayList<>();
+                        printers.add((new PrinterInfo.Builder(printerId, PRINTER_NAME,
+                                PrinterInfo.STATUS_IDLE))
+                                .setCapabilities(capBuilder.apply(printerId)).build());
+
+                        session.addPrinters(printers);
+
+                        onPrinterDiscoverySessionCreateCalled();
+                        return null;
+                    }
+                }, null, null, null, null, null, new Answer<Void>() {
+                    @Override
+                    public Void answer(InvocationOnMock invocation) {
+                        onPrinterDiscoverySessionDestroyCalled();
+                        return null;
+                    }
+                });
+
+        // Create the service callbacks for the first print service.
+        PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
+                new Answer<PrinterDiscoverySessionCallbacks>() {
+                    @Override
+                    public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+                        return firstSessionCallbacks;
+                    }
+                }, null, null);
+
+        // Configure the print services.
+        FirstPrintService.setCallbacks(firstServiceCallbacks);
+        SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
+
+        final PrintAttributes[] layoutAttributes = new PrintAttributes[1];
+
+        PrintDocumentAdapter adapter = createMockPrintDocumentAdapter(
+                new Answer<Void>() {
+                    @Override
+                    public Void answer(InvocationOnMock invocation) throws Throwable {
+                        LayoutResultCallback callback = (LayoutResultCallback) invocation
+                                .getArguments()[3];
+                        PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+                                .setPageCount(1)
+                                .build();
+                        layoutAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+
+                        callback.onLayoutFinished(info, true);
+                        return null;
+                    }
+                },
+                new Answer<Void>() {
+                    @Override
+                    public Void answer(InvocationOnMock invocation) throws Throwable {
+                        Object[] args = invocation.getArguments();
+                        PageRange[] pages = (PageRange[]) args[0];
+                        ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+                        WriteResultCallback callback = (WriteResultCallback) args[3];
+
+                        writeBlankPages(layoutAttributes[0], fd, pages[0].getStart(),
+                                pages[0].getEnd());
+                        fd.close();
+
+                        callback.onWriteFinished(pages);
+                        return null;
+                    }
+                }, null);
+
+        // Start printing.
+        print(adapter);
+
+        // make sure that options does not crash
+        openPrintOptions();
+
+        // Select printer under test
+        selectPrinter(PRINTER_NAME);
+
+        clickPrintButton();
+
+        answerPrintServicesWarning(true);
+
+        test.accept(layoutAttributes[0]);
+
+        waitForPrinterDiscoverySessionDestroyCallbackCalled();
+    }
+
+    /**
+     * That that you use a default color that is not in the allowed colors. This is allowed because
+     * of historical reasons.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    public void testInvalidDefaultColor() throws Exception {
+        testPrinterCapabilityInfo(
+                (printerId) -> (new PrinterCapabilitiesInfo.Builder(printerId))
+                        .addMediaSize(MediaSize.ISO_A4, true)
+                        .addResolution(RESOLUTION_300, true)
+                        .setColorModes(PrintAttributes.COLOR_MODE_MONOCHROME,
+                                PrintAttributes.COLOR_MODE_COLOR).build(),
+                (layoutAttributes) -> assertEquals(layoutAttributes.getColorMode(),
+                        PrintAttributes.COLOR_MODE_MONOCHROME));
+    }
+
+    /**
+     * That that you use a default duplex mode that is not in the allowed duplex modes. This is
+     * allowed because of historical reasons.
+     *
+     * @throws Exception If anything is unexpected
+     */
+    public void testInvalidDefaultDuplexMode() throws Exception {
+        testPrinterCapabilityInfo(
+                (printerId) -> (new PrinterCapabilitiesInfo.Builder(printerId))
+                        .addMediaSize(MediaSize.ISO_A4, true)
+                        .addResolution(RESOLUTION_300, true)
+                        .setColorModes(PrintAttributes.COLOR_MODE_MONOCHROME,
+                                PrintAttributes.COLOR_MODE_MONOCHROME)
+                        .setDuplexModes(PrintAttributes.DUPLEX_MODE_LONG_EDGE
+                                | PrintAttributes.DUPLEX_MODE_NONE,
+                                PrintAttributes.DUPLEX_MODE_SHORT_EDGE).build(),
+                (layoutAttributes) -> assertTrue(layoutAttributes.getDuplexMode() ==
+                        PrintAttributes.DUPLEX_MODE_LONG_EDGE || layoutAttributes.getDuplexMode() ==
+                        PrintAttributes.DUPLEX_MODE_NONE));
+    }
 }
diff --git a/tests/tests/provider/src/android/provider/cts/BlockedNumberBackupRestoreTest.java b/tests/tests/provider/src/android/provider/cts/BlockedNumberBackupRestoreTest.java
index 5ea4caf..adf558b 100644
--- a/tests/tests/provider/src/android/provider/cts/BlockedNumberBackupRestoreTest.java
+++ b/tests/tests/provider/src/android/provider/cts/BlockedNumberBackupRestoreTest.java
@@ -42,6 +42,7 @@
     private Context mContext;
     private UiAutomation mUiAutomation;
     private String mOldTransport;
+    private boolean mOldBackupEnabled;
     private boolean mHasFeature;
 
     @Override
@@ -59,6 +60,7 @@
 
             mOldTransport = ProviderTestUtils.setBackupTransport(
                     LOCAL_BACKUP_COMPONENT, mUiAutomation);
+            mOldBackupEnabled = ProviderTestUtils.setBackupEnabled(true, mUiAutomation);
             clearBlockedNumbers();
             wipeBackup();
         }
@@ -69,6 +71,7 @@
         if (mHasFeature) {
             wipeBackup();
             clearBlockedNumbers();
+            ProviderTestUtils.setBackupEnabled(mOldBackupEnabled, mUiAutomation);
             ProviderTestUtils.setBackupTransport(mOldTransport, mUiAutomation);
             ProviderTestUtils.setDefaultSmsApp(false, mContext.getPackageName(), mUiAutomation);
         }
diff --git a/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java b/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
index 874a0a7..e2ed68d 100644
--- a/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
+++ b/tests/tests/provider/src/android/provider/cts/ProviderTestUtils.java
@@ -34,7 +34,9 @@
  */
 public class ProviderTestUtils {
 
-    static final int BACKUP_TIMEOUT_MILLIS = 4000;
+    private static final int BACKUP_TIMEOUT_MILLIS = 4000;
+    private static final Pattern BMGR_ENABLED_PATTERN = Pattern.compile(
+            "^Backup Manager currently (enabled|disabled)$");
 
     static void setDefaultSmsApp(boolean setToSmsApp, String packageName, UiAutomation uiAutomation)
             throws Exception {
@@ -73,6 +75,22 @@
         }
     }
 
+    static boolean setBackupEnabled(boolean enable, UiAutomation uiAutomation) throws Exception {
+        // Check to see the previous state of the backup service
+        boolean previouslyEnabled = false;
+        String output = executeShellCommand("bmgr enabled", uiAutomation);
+        Matcher matcher = BMGR_ENABLED_PATTERN.matcher(output.trim());
+        if (matcher.find()) {
+            previouslyEnabled = "enabled".equals(matcher.group(1));
+        } else {
+            throw new RuntimeException("Backup output format changed.  No longer matches"
+                    + " expected regex: " + BMGR_ENABLED_PATTERN + "\nactual: '" + output + "'");
+        }
+
+        executeShellCommand("bmgr enable " + enable, uiAutomation);
+        return previouslyEnabled;
+    }
+
     static boolean hasBackupTransport(String transport, UiAutomation uiAutomation)
             throws Exception {
         String output = executeShellCommand("bmgr list transports", uiAutomation);
diff --git a/tests/tests/provider/src/android/provider/cts/SmsBackupRestoreTest.java b/tests/tests/provider/src/android/provider/cts/SmsBackupRestoreTest.java
index f5e3033..fad1019 100644
--- a/tests/tests/provider/src/android/provider/cts/SmsBackupRestoreTest.java
+++ b/tests/tests/provider/src/android/provider/cts/SmsBackupRestoreTest.java
@@ -24,6 +24,7 @@
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.net.Uri;
 import android.provider.BaseColumns;
@@ -65,6 +66,8 @@
     private ContentResolver mContentResolver;
     private UiAutomation mUiAutomation;
     private String mOldTransport;
+    private boolean mOldBackupEnabled;
+    private boolean mHasFeature;
 
     @Override
     protected void setUp() throws Exception {
@@ -74,21 +77,35 @@
         mContext = getInstrumentation().getContext();
         mContentResolver = mContext.getContentResolver();
         mUiAutomation = getInstrumentation().getUiAutomation();
-        ProviderTestUtils.setDefaultSmsApp(true, mContext.getPackageName(), mUiAutomation);
-        mOldTransport = ProviderTestUtils.setBackupTransport(LOCAL_BACKUP_COMPONENT, mUiAutomation);
-        clearMessages();
-        wipeBackup();
+        mHasFeature = isFeatureSupported();
+        if (mHasFeature) {
+            ProviderTestUtils.setDefaultSmsApp(true, mContext.getPackageName(), mUiAutomation);
+            mOldTransport =
+                    ProviderTestUtils.setBackupTransport(LOCAL_BACKUP_COMPONENT, mUiAutomation);
+            mOldBackupEnabled = ProviderTestUtils.setBackupEnabled(true, mUiAutomation);
+            clearMessages();
+            wipeBackup();
+        }
     }
 
     @Override
     protected void tearDown() throws Exception {
-        wipeBackup();
-        clearMessages();
-        ProviderTestUtils.setBackupTransport(mOldTransport, mUiAutomation);
-        ProviderTestUtils.setDefaultSmsApp(false, mContext.getPackageName(), mUiAutomation);
+        if (mHasFeature) {
+            wipeBackup();
+            clearMessages();
+            ProviderTestUtils.setBackupEnabled(mOldBackupEnabled, mUiAutomation);
+            ProviderTestUtils.setBackupTransport(mOldTransport, mUiAutomation);
+            ProviderTestUtils.setDefaultSmsApp(false, mContext.getPackageName(), mUiAutomation);
+        }
+
         super.tearDown();
     }
 
+    private boolean isFeatureSupported() throws Exception {
+        return (ProviderTestUtils.hasBackupTransport(LOCAL_BACKUP_COMPONENT, mUiAutomation)
+                && mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY));
+    }
+
     private void clearMessages() {
         mContentResolver.delete(Telephony.Sms.CONTENT_URI, SMS_SELECTION, smsAddressBody1);
         mContentResolver.delete(Telephony.Sms.CONTENT_URI, SMS_SELECTION, smsAddressBody2);
@@ -117,8 +134,9 @@
      * @throws Exception
      */
     public void testSmsBackupRestore() throws Exception {
-        if (!ProviderTestUtils.hasBackupTransport(LOCAL_BACKUP_COMPONENT, mUiAutomation)) {
+        if (!mHasFeature) {
             Log.i(TAG, "skipping testSmsBackupRestore");
+            return;
         }
 
         ContentValues smsContentValues[] = new ContentValues[] {
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/AllocationCopyPaddedTest.java b/tests/tests/renderscript/src/android/renderscript/cts/AllocationCopyPaddedTest.java
index 6e74cb3..bb10716 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/AllocationCopyPaddedTest.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/AllocationCopyPaddedTest.java
@@ -45,7 +45,7 @@
                 break;
             }
         }
-        assertTrue("test_AllocationCopyTo_1D_Padded_Byte Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_Byte3_1D Failed, output array does not match input",
                    result);
     }
 
@@ -54,7 +54,7 @@
         int width = random.nextInt(128);
         int height = random.nextInt(128);
         int arr_len = width * height * 3;
-        
+
         byte[] inArray = new byte[arr_len];
         byte[] outArray = new byte[arr_len];
         random.nextBytes(inArray);
@@ -73,7 +73,7 @@
                 break;
             }
         }
-        assertTrue("test_2D_AllocationCopyTo_Padded_Byte Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_Byte3_2D Failed, output array does not match input",
                    result);
     }
 
@@ -102,7 +102,7 @@
                 break;
             }
         }
-        assertTrue("test_AllocationCopyTo_3D_Padded_Byte Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_Byte3_3D Failed, output array does not match input",
                    result);
     }
 
@@ -146,7 +146,7 @@
         int width = random.nextInt(128);
         int height = random.nextInt(128);
         int arr_len = width * height * 3;
-        
+
         short[] inArray = new short[arr_len];
         short[] outArray = new short[arr_len];
 
@@ -240,7 +240,7 @@
                 break;
             }
         }
-        assertTrue("test_AllocationCopyTo_1D_Padded_Int Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_Int3_1D Failed, output array does not match input",
                    result);
     }
 
@@ -249,7 +249,7 @@
         int width = random.nextInt(128);
         int height = random.nextInt(128);
         int arr_len = width * height * 3;
-        
+
         int[] inArray = new int[arr_len];
         int[] outArray = new int[arr_len];
 
@@ -271,7 +271,7 @@
                 break;
             }
         }
-        assertTrue("test_AllocationCopyTo_2D_Padded_Int Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_Int3_2D Failed, output array does not match input",
                    result);
     }
 
@@ -303,7 +303,7 @@
                 break;
             }
         }
-        assertTrue("test_AllocationCopyTo_3D_Padded_Int Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_Int3_3D Failed, output array does not match input",
                    result);
     }
 
@@ -333,7 +333,7 @@
                 break;
             }
         }
-        assertTrue("test_AllocationCopyTo_1D_Padded_Float Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_Float3_1D Failed, output array does not match input",
                    result);
     }
     public void test_AllocationPadded_Float3_2D() {
@@ -363,7 +363,7 @@
                 break;
             }
         }
-        assertTrue("test_AllocationCopyTo_2D_Padded_Float Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_Float3_2D Failed, output array does not match input",
                    result);
     }
     public void test_AllocationPadded_Float3_3D() {
@@ -394,7 +394,7 @@
                 break;
             }
         }
-        assertTrue("test_AllocationCopyTo_3D_Padded_Float Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_Float3_3D Failed, output array does not match input",
                    result);
     }
 
@@ -424,7 +424,7 @@
                 break;
             }
         }
-        assertTrue("test_AllocationCopyTo_1D_Padded_Double Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_Double3_1D Failed, output array does not match input",
                    result);
     }
     public void test_AllocationPadded_Double3_2D() {
@@ -454,7 +454,7 @@
                 break;
             }
         }
-        assertTrue("test_AllocationCopyTo_2D_Padded_Double Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_Double3_2D Failed, output array does not match input",
                    result);
     }
     public void test_AllocationPadded_Double3_3D() {
@@ -485,7 +485,7 @@
                 break;
             }
         }
-        assertTrue("test_AllocationCopyTo_3D_Padded_Double Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_Double3_3D Failed, output array does not match input",
                    result);
     }
 
@@ -515,7 +515,7 @@
                 break;
             }
         }
-        assertTrue("test_AllocationCopyTo_1D_Padded_Long Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_Long3_1D Failed, output array does not match input",
                    result);
     }
 
@@ -524,7 +524,7 @@
         int width = random.nextInt(128);
         int height = random.nextInt(128);
         int arr_len = width * height * 3;
-        
+
         long[] inArray = new long[arr_len];
         long[] outArray = new long[arr_len];
 
@@ -546,7 +546,7 @@
                 break;
             }
         }
-        assertTrue("test_AllocationCopyTo_2D_Padded_Long Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_Long3_2D Failed, output array does not match input",
                    result);
     }
 
@@ -578,7 +578,7 @@
                 break;
             }
         }
-        assertTrue("test_AllocationCopyTo_3D_Padded_Long Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_Long3_3D Failed, output array does not match input",
                    result);
     }
 
@@ -614,7 +614,7 @@
                 break;
             }
         }
-        assertTrue("test_copy1DRangeTo_Padded_Byte Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_copy1DRangeTo_Byte3, output array does not match input",
                    result);
     }
 
@@ -625,7 +625,7 @@
 
         short[] inArray = new short[arr_len];
         short[] outArray = new short[arr_len];
-        
+
         for (int i = 0; i < arr_len; i++) {
             inArray[i] = (short)random.nextInt();
         }
@@ -695,7 +695,7 @@
                 break;
             }
         }
-        assertTrue("test_copy1DRangeTo_Padded_Int Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_copy1DRangeTo_Int3 Failed, output array does not match input",
                    result);
     }
 
@@ -733,7 +733,7 @@
                 break;
             }
         }
-        assertTrue("test_copy1DRangeTo_Padded_Float Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_copy1DRangeTo_Float3 Failed, output array does not match input",
                    result);
     }
 
@@ -771,7 +771,7 @@
                 break;
             }
         }
-        assertTrue("test_copy1DRangeTo_Padded_Long Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_copy1DRangeTo_Long3 Failed, output array does not match input",
                    result);
     }
 
@@ -803,7 +803,7 @@
                 break;
             }
         }
-        assertTrue("test_copy2DRangeTo_Padded_Byte Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_copy2DRangeTo_Byte3 Failed, output array does not match input",
                    result);
     }
 
@@ -819,7 +819,7 @@
 
         short[] inArray = new short[arr_len];
         short[] outArray = new short[arr_len];
-        
+
         for (int i = 0; i < arr_len; i++) {
             inArray[i] = (short)random.nextInt();
         }
@@ -878,7 +878,7 @@
                 break;
             }
         }
-        assertTrue("test_copy2DRangeTo_Padded_Int Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_copy2DRangeTo_Int3 Failed, output array does not match input",
                    result);
     }
 
@@ -913,7 +913,7 @@
                 break;
             }
         }
-        assertTrue("test_copy2DRangeTo_Padded_Float Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_copy2DRangeTo_Float3 Failed, output array does not match input",
                    result);
     }
 
@@ -948,7 +948,7 @@
                 break;
             }
         }
-        assertTrue("test_copy2DRangeTo_Padded_Long Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_copy2DRangeTo_Long3 Failed, output array does not match input",
                    result);
     }
 
@@ -984,7 +984,7 @@
                 break;
             }
         }
-        assertTrue("test_copy1DRangeToUnchecked_Padded_Byte Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_copy1DRangeToUnchecked_Byte3 Failed, output array does not match input",
                    result);
     }
 
@@ -995,7 +995,7 @@
 
         short[] inArray = new short[arr_len];
         short[] outArray = new short[arr_len];
-        
+
         for (int i = 0; i < arr_len; i++) {
             inArray[i] = (short)random.nextInt();
         }
@@ -1065,7 +1065,7 @@
                 break;
             }
         }
-        assertTrue("test_copy1DRangeToUnchecked_1D_Padded_Int Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_copy1DRangeToUnchecked_Int3 Failed, output array does not match input",
                    result);
     }
 
@@ -1103,7 +1103,7 @@
                 break;
             }
         }
-        assertTrue("test_copy1DRangeToUnchecked_Padded_Float Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_copy1DRangeToUnchecked_Float3 Failed, output array does not match input",
                    result);
     }
 
@@ -1141,7 +1141,7 @@
                 break;
             }
         }
-        assertTrue("test_copy1DRangeToUnchecked_Padded_Long Failed, output array does not match input",
+        assertTrue("test_AllocationPadded_copy1DRangeToUnchecked_Long3 Failed, output array does not match input",
                    result);
     }
 }
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/CoreMathVerifier.java b/tests/tests/renderscript/src/android/renderscript/cts/CoreMathVerifier.java
index 85f85a4..bc13144 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/CoreMathVerifier.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/CoreMathVerifier.java
@@ -1006,10 +1006,10 @@
         Target.Floaty in = t.newFloaty(d);
         double min = Math.tan(in.min());
         double max = Math.tan(in.max());
-        /* If the tan of the min is greater than that of the max,
-         * we spanned a discontinuity.
+        /* If difference between in.max() and in.min() is larger than PI or if the tan of the min is
+         * greater than that of the max, we spanned a discontinuity.
          */
-        if (min > max) {
+        if (in.max() - in.min() > Math.PI || min > max) {
             return any(t);
         } else {
             return t.newFloaty(Math.tan(d), min, max);
@@ -1020,10 +1020,10 @@
         Target.Floaty in = t.new32(f);
         float min = tan(in.min32());
         float max = tan(in.max32());
-        /* If the tan of the min is greater than that of the max,
-         * we spanned a discontinuity.
+        /* If difference between in.max() and in.min() is larger than PI or if the tan of the min is
+         * greater than that of the max, we spanned a discontinuity.
          */
-        if (min > max) {
+        if (in.max() - in.min() > Math.PI || min > max) {
             return any32(t);
         } else {
             return t.new32(tan(f), min, max);
@@ -1050,10 +1050,11 @@
         Target.Floaty in = t.multiply(t.newFloaty(d), pi(t));
         double min = Math.tan(in.min());
         double max = Math.tan(in.max());
-        /* If the tan of the min is greater than that of the max,
-         * we spanned a discontinuity.
+
+        /* If difference between in.max() and in.min() is larger than PI or if the tan of the min is
+         * greater than that of the max, we spanned a discontinuity.
          */
-        if (min > max) {
+        if (in.max() - in.min() > Math.PI || min > max) {
             return any(t);
         } else {
             return t.newFloaty(Math.tan(in.mid()), min, max);
@@ -1064,10 +1065,10 @@
         Target.Floaty in = t.multiply(t.new32(f), pi32(t));
         float min = tan(in.min32());
         float max = tan(in.max32());
-        /* If the tan of the min is greater than that of the max,
-         * we spanned a discontinuity.
+        /* If difference between in.max() and in.min() is larger than PI or if the tan of the min is
+         * greater than that of the max, we spanned a discontinuity.
          */
-        if (min > max) {
+        if (in.max() - in.min() > Math.PI || min > max) {
             return any32(t);
         } else {
             return t.new32(tan(in.mid32()), min, max);
@@ -2599,6 +2600,31 @@
         args.out = exp2(args.inV, t);
     }
 
+    static public String verifyNativeExpm1(TestNativeExpm1.ArgumentsHalfHalf args, Target t) {
+        // Acceptable error for native_expm1 is:
+        //     < 2^-11 in [-Inf, 0.6]
+        //     3 ulp outside
+        double extraAllowedError = 0.;
+        int ulpFactor;
+        if (args.inVDouble < 0.6) {
+            ulpFactor = 0;
+            extraAllowedError = 0.00048828125; // 2^-11
+        } else {
+            ulpFactor = 3;
+        }
+        t.setPrecision(ulpFactor, ulpFactor);
+
+        Target.Floaty expectedOut = expm1(args.inVDouble, t);
+        if (!expectedOut.couldBe(args.outDouble, extraAllowedError)) {
+            StringBuilder message = new StringBuilder();
+            message.append("Ulp Factor: " + Integer.toString(ulpFactor) + "\n");
+            message.append("Extra allowed error: " + Double.toString(extraAllowedError) + "\n");
+            message.append("Expected output out: " + expectedOut.toString() + "\n");
+            return message.toString();
+        }
+        return null;
+    }
+
     static public void computeNativeExpm1(TestNativeExpm1.ArgumentsFloatFloat args, Target t) {
         t.setPrecision(NATIVE_PRECISION, NATIVE_PRECISION);
         args.out = expm1(args.inV, t);
@@ -2835,6 +2861,35 @@
         args.out = sqrt(args.inV, t);
     }
 
+    static public String verifyNativeTan(TestNativeTan.ArgumentsHalfHalf args, Target t) {
+        // Precision for native_tan is as follows:
+        //     For integral n:
+        //         8 ulp in [(n-0.45) pi, (n+0.45) pi]
+        //         2048 ulp in [(n+0.45) pi, (n+0.55) pi]"
+
+        // Compute the fractional part of args.inVDouble / pi
+        double absoluteValueOverPi = Math.abs(args.inVDouble) / Math.PI;
+        double fract = absoluteValueOverPi - Math.floor(absoluteValueOverPi);
+
+        int ulpFactor;
+        if (0.45 <= fract && fract <= 0.55) {
+            ulpFactor = 2048;
+        } else {
+            ulpFactor = 8;
+        }
+        t.setPrecision(ulpFactor, ulpFactor);
+
+        Target.Floaty expectedOut = tan(args.inVDouble, t);
+        if (!expectedOut.couldBe(args.outDouble)) {
+            StringBuilder message = new StringBuilder();
+            message.append("Ulp Factor: " + Integer.toString(ulpFactor) + "\n");
+            message.append("Expected output out: " + expectedOut.toString() + "\n");
+            return message.toString();
+        }
+
+        return null;
+    }
+
     static public void computeNativeTan(TestNativeTan.ArgumentsFloatFloat args, Target t) {
         t.setPrecision(NATIVE_PRECISION, NATIVE_PRECISION);
         args.out = tan(args.inV, t);
@@ -2850,6 +2905,35 @@
         args.out = tanh(args.inV, t);
     }
 
+    static public String verifyNativeTanpi(TestNativeTanpi.ArgumentsHalfHalf args, Target t) {
+        // Precision for native_tan is as follows:
+        //     For integral n:
+        //         8 ulp in [(n-0.45), (n+0.45)]
+        //         2048 ulp in [(n+0.45), (n+0.55)]"
+
+        // Compute the fractional part of args.inVDouble
+        double absoluteValue = Math.abs(args.inVDouble);
+        double fract = absoluteValue - Math.floor(absoluteValue);
+
+        int ulpFactor;
+        if (0.45 <= fract && fract <= 0.55) {
+            ulpFactor = 2048;
+        } else {
+            ulpFactor = 8;
+        }
+        t.setPrecision(ulpFactor, ulpFactor);
+
+        Target.Floaty expectedOut = tanpi(args.inVDouble, t);
+        if (!expectedOut.couldBe(args.outDouble)) {
+            StringBuilder message = new StringBuilder();
+            message.append("Ulp Factor: " + Integer.toString(ulpFactor) + "\n");
+            message.append("Expected output out: " + expectedOut.toString() + "\n");
+            return message.toString();
+        }
+
+        return null;
+    }
+
     static public void computeNativeTanpi(TestNativeTanpi.ArgumentsFloatFloat args, Target t) {
         t.setPrecision(NATIVE_PRECISION, NATIVE_PRECISION);
         args.out = tanpi(args.inV, t);
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeExpm1.java b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeExpm1.java
index edae2df..3b4412b 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeExpm1.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeExpm1.java
@@ -318,10 +318,293 @@
                 (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
     }
 
+    public class ArgumentsHalfHalf {
+        public short inV;
+        public double inVDouble;
+        public short out;
+        public double outDouble;
+    }
+
+    private void checkNativeExpm1HalfHalf() {
+        Allocation inV = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 1, 0x1f7c28dl, false);
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 1), INPUTSIZE);
+            script.forEach_testNativeExpm1HalfHalf(inV, out);
+            verifyResultsNativeExpm1HalfHalf(inV, out, false);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeExpm1HalfHalf: " + e.toString());
+        }
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 1), INPUTSIZE);
+            scriptRelaxed.forEach_testNativeExpm1HalfHalf(inV, out);
+            verifyResultsNativeExpm1HalfHalf(inV, out, true);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeExpm1HalfHalf: " + e.toString());
+        }
+    }
+
+    private void verifyResultsNativeExpm1HalfHalf(Allocation inV, Allocation out, boolean relaxed) {
+        short[] arrayInV = new short[INPUTSIZE * 1];
+        Arrays.fill(arrayInV, (short) 42);
+        inV.copyTo(arrayInV);
+        short[] arrayOut = new short[INPUTSIZE * 1];
+        Arrays.fill(arrayOut, (short) 42);
+        out.copyTo(arrayOut);
+        StringBuilder message = new StringBuilder();
+        boolean errorFound = false;
+        for (int i = 0; i < INPUTSIZE; i++) {
+            for (int j = 0; j < 1 ; j++) {
+                // Extract the inputs.
+                ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+                args.inV = arrayInV[i];
+                args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+                // Extract the outputs.
+                args.out = arrayOut[i * 1 + j];
+                args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+                // Ask the CoreMathVerifier to validate.
+                Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+                String errorMessage = CoreMathVerifier.verifyNativeExpm1(args, target);
+                boolean valid = errorMessage == null;
+                if (!valid) {
+                    if (!errorFound) {
+                        errorFound = true;
+                        message.append("Input inV: ");
+                        appendVariableToMessage(message, args.inV);
+                        message.append("\n");
+                        message.append("Output out: ");
+                        appendVariableToMessage(message, args.out);
+                        message.append("\n");
+                        message.append("\n");
+                        message.append("Output out (in double): ");
+                        appendVariableToMessage(message, args.outDouble);
+                        message.append("\n");
+                        message.append(errorMessage);
+                        message.append("Errors at");
+                    }
+                    message.append(" [");
+                    message.append(Integer.toString(i));
+                    message.append(", ");
+                    message.append(Integer.toString(j));
+                    message.append("]");
+                }
+            }
+        }
+        assertFalse("Incorrect output for checkNativeExpm1HalfHalf" +
+                (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+    }
+
+    private void checkNativeExpm1Half2Half2() {
+        Allocation inV = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 2, 0xddb33a87l, false);
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+            script.forEach_testNativeExpm1Half2Half2(inV, out);
+            verifyResultsNativeExpm1Half2Half2(inV, out, false);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeExpm1Half2Half2: " + e.toString());
+        }
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+            scriptRelaxed.forEach_testNativeExpm1Half2Half2(inV, out);
+            verifyResultsNativeExpm1Half2Half2(inV, out, true);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeExpm1Half2Half2: " + e.toString());
+        }
+    }
+
+    private void verifyResultsNativeExpm1Half2Half2(Allocation inV, Allocation out, boolean relaxed) {
+        short[] arrayInV = new short[INPUTSIZE * 2];
+        Arrays.fill(arrayInV, (short) 42);
+        inV.copyTo(arrayInV);
+        short[] arrayOut = new short[INPUTSIZE * 2];
+        Arrays.fill(arrayOut, (short) 42);
+        out.copyTo(arrayOut);
+        StringBuilder message = new StringBuilder();
+        boolean errorFound = false;
+        for (int i = 0; i < INPUTSIZE; i++) {
+            for (int j = 0; j < 2 ; j++) {
+                // Extract the inputs.
+                ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+                args.inV = arrayInV[i * 2 + j];
+                args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+                // Extract the outputs.
+                args.out = arrayOut[i * 2 + j];
+                args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+                // Ask the CoreMathVerifier to validate.
+                Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+                String errorMessage = CoreMathVerifier.verifyNativeExpm1(args, target);
+                boolean valid = errorMessage == null;
+                if (!valid) {
+                    if (!errorFound) {
+                        errorFound = true;
+                        message.append("Input inV: ");
+                        appendVariableToMessage(message, args.inV);
+                        message.append("\n");
+                        message.append("Output out: ");
+                        appendVariableToMessage(message, args.out);
+                        message.append("\n");
+                        message.append("\n");
+                        message.append("Output out (in double): ");
+                        appendVariableToMessage(message, args.outDouble);
+                        message.append("\n");
+                        message.append(errorMessage);
+                        message.append("Errors at");
+                    }
+                    message.append(" [");
+                    message.append(Integer.toString(i));
+                    message.append(", ");
+                    message.append(Integer.toString(j));
+                    message.append("]");
+                }
+            }
+        }
+        assertFalse("Incorrect output for checkNativeExpm1Half2Half2" +
+                (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+    }
+
+    private void checkNativeExpm1Half3Half3() {
+        Allocation inV = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 3, 0x3cbaff7bl, false);
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+            script.forEach_testNativeExpm1Half3Half3(inV, out);
+            verifyResultsNativeExpm1Half3Half3(inV, out, false);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeExpm1Half3Half3: " + e.toString());
+        }
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+            scriptRelaxed.forEach_testNativeExpm1Half3Half3(inV, out);
+            verifyResultsNativeExpm1Half3Half3(inV, out, true);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeExpm1Half3Half3: " + e.toString());
+        }
+    }
+
+    private void verifyResultsNativeExpm1Half3Half3(Allocation inV, Allocation out, boolean relaxed) {
+        short[] arrayInV = new short[INPUTSIZE * 4];
+        Arrays.fill(arrayInV, (short) 42);
+        inV.copyTo(arrayInV);
+        short[] arrayOut = new short[INPUTSIZE * 4];
+        Arrays.fill(arrayOut, (short) 42);
+        out.copyTo(arrayOut);
+        StringBuilder message = new StringBuilder();
+        boolean errorFound = false;
+        for (int i = 0; i < INPUTSIZE; i++) {
+            for (int j = 0; j < 3 ; j++) {
+                // Extract the inputs.
+                ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+                args.inV = arrayInV[i * 4 + j];
+                args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+                // Extract the outputs.
+                args.out = arrayOut[i * 4 + j];
+                args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+                // Ask the CoreMathVerifier to validate.
+                Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+                String errorMessage = CoreMathVerifier.verifyNativeExpm1(args, target);
+                boolean valid = errorMessage == null;
+                if (!valid) {
+                    if (!errorFound) {
+                        errorFound = true;
+                        message.append("Input inV: ");
+                        appendVariableToMessage(message, args.inV);
+                        message.append("\n");
+                        message.append("Output out: ");
+                        appendVariableToMessage(message, args.out);
+                        message.append("\n");
+                        message.append("\n");
+                        message.append("Output out (in double): ");
+                        appendVariableToMessage(message, args.outDouble);
+                        message.append("\n");
+                        message.append(errorMessage);
+                        message.append("Errors at");
+                    }
+                    message.append(" [");
+                    message.append(Integer.toString(i));
+                    message.append(", ");
+                    message.append(Integer.toString(j));
+                    message.append("]");
+                }
+            }
+        }
+        assertFalse("Incorrect output for checkNativeExpm1Half3Half3" +
+                (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+    }
+
+    private void checkNativeExpm1Half4Half4() {
+        Allocation inV = createRandomAllocation(mRS, Element.DataType.FLOAT_16, 4, 0x9bc2c46fl, false);
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+            script.forEach_testNativeExpm1Half4Half4(inV, out);
+            verifyResultsNativeExpm1Half4Half4(inV, out, false);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeExpm1Half4Half4: " + e.toString());
+        }
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+            scriptRelaxed.forEach_testNativeExpm1Half4Half4(inV, out);
+            verifyResultsNativeExpm1Half4Half4(inV, out, true);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeExpm1Half4Half4: " + e.toString());
+        }
+    }
+
+    private void verifyResultsNativeExpm1Half4Half4(Allocation inV, Allocation out, boolean relaxed) {
+        short[] arrayInV = new short[INPUTSIZE * 4];
+        Arrays.fill(arrayInV, (short) 42);
+        inV.copyTo(arrayInV);
+        short[] arrayOut = new short[INPUTSIZE * 4];
+        Arrays.fill(arrayOut, (short) 42);
+        out.copyTo(arrayOut);
+        StringBuilder message = new StringBuilder();
+        boolean errorFound = false;
+        for (int i = 0; i < INPUTSIZE; i++) {
+            for (int j = 0; j < 4 ; j++) {
+                // Extract the inputs.
+                ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+                args.inV = arrayInV[i * 4 + j];
+                args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+                // Extract the outputs.
+                args.out = arrayOut[i * 4 + j];
+                args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+                // Ask the CoreMathVerifier to validate.
+                Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+                String errorMessage = CoreMathVerifier.verifyNativeExpm1(args, target);
+                boolean valid = errorMessage == null;
+                if (!valid) {
+                    if (!errorFound) {
+                        errorFound = true;
+                        message.append("Input inV: ");
+                        appendVariableToMessage(message, args.inV);
+                        message.append("\n");
+                        message.append("Output out: ");
+                        appendVariableToMessage(message, args.out);
+                        message.append("\n");
+                        message.append("\n");
+                        message.append("Output out (in double): ");
+                        appendVariableToMessage(message, args.outDouble);
+                        message.append("\n");
+                        message.append(errorMessage);
+                        message.append("Errors at");
+                    }
+                    message.append(" [");
+                    message.append(Integer.toString(i));
+                    message.append(", ");
+                    message.append(Integer.toString(j));
+                    message.append("]");
+                }
+            }
+        }
+        assertFalse("Incorrect output for checkNativeExpm1Half4Half4" +
+                (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+    }
+
     public void testNativeExpm1() {
         checkNativeExpm1FloatFloat();
         checkNativeExpm1Float2Float2();
         checkNativeExpm1Float3Float3();
         checkNativeExpm1Float4Float4();
+        checkNativeExpm1HalfHalf();
+        checkNativeExpm1Half2Half2();
+        checkNativeExpm1Half3Half3();
+        checkNativeExpm1Half4Half4();
     }
 }
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeExpm1.rs b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeExpm1.rs
index 2cfee07..a965138 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeExpm1.rs
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeExpm1.rs
@@ -35,3 +35,19 @@
 float4 __attribute__((kernel)) testNativeExpm1Float4Float4(float4 inV) {
     return native_expm1(inV);
 }
+
+half __attribute__((kernel)) testNativeExpm1HalfHalf(half inV) {
+    return native_expm1(inV);
+}
+
+half2 __attribute__((kernel)) testNativeExpm1Half2Half2(half2 inV) {
+    return native_expm1(inV);
+}
+
+half3 __attribute__((kernel)) testNativeExpm1Half3Half3(half3 inV) {
+    return native_expm1(inV);
+}
+
+half4 __attribute__((kernel)) testNativeExpm1Half4Half4(half4 inV) {
+    return native_expm1(inV);
+}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTan.java b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTan.java
index c6c32b6..b43ff71 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTan.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTan.java
@@ -318,10 +318,293 @@
                 (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
     }
 
+    public class ArgumentsHalfHalf {
+        public short inV;
+        public double inVDouble;
+        public short out;
+        public double outDouble;
+    }
+
+    private void checkNativeTanHalfHalf() {
+        Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_16, 1, 0x3e70ec45l, -314, 314);
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 1), INPUTSIZE);
+            script.forEach_testNativeTanHalfHalf(inV, out);
+            verifyResultsNativeTanHalfHalf(inV, out, false);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanHalfHalf: " + e.toString());
+        }
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 1), INPUTSIZE);
+            scriptRelaxed.forEach_testNativeTanHalfHalf(inV, out);
+            verifyResultsNativeTanHalfHalf(inV, out, true);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanHalfHalf: " + e.toString());
+        }
+    }
+
+    private void verifyResultsNativeTanHalfHalf(Allocation inV, Allocation out, boolean relaxed) {
+        short[] arrayInV = new short[INPUTSIZE * 1];
+        Arrays.fill(arrayInV, (short) 42);
+        inV.copyTo(arrayInV);
+        short[] arrayOut = new short[INPUTSIZE * 1];
+        Arrays.fill(arrayOut, (short) 42);
+        out.copyTo(arrayOut);
+        StringBuilder message = new StringBuilder();
+        boolean errorFound = false;
+        for (int i = 0; i < INPUTSIZE; i++) {
+            for (int j = 0; j < 1 ; j++) {
+                // Extract the inputs.
+                ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+                args.inV = arrayInV[i];
+                args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+                // Extract the outputs.
+                args.out = arrayOut[i * 1 + j];
+                args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+                // Ask the CoreMathVerifier to validate.
+                Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+                String errorMessage = CoreMathVerifier.verifyNativeTan(args, target);
+                boolean valid = errorMessage == null;
+                if (!valid) {
+                    if (!errorFound) {
+                        errorFound = true;
+                        message.append("Input inV: ");
+                        appendVariableToMessage(message, args.inV);
+                        message.append("\n");
+                        message.append("Output out: ");
+                        appendVariableToMessage(message, args.out);
+                        message.append("\n");
+                        message.append("\n");
+                        message.append("Output out (in double): ");
+                        appendVariableToMessage(message, args.outDouble);
+                        message.append("\n");
+                        message.append(errorMessage);
+                        message.append("Errors at");
+                    }
+                    message.append(" [");
+                    message.append(Integer.toString(i));
+                    message.append(", ");
+                    message.append(Integer.toString(j));
+                    message.append("]");
+                }
+            }
+        }
+        assertFalse("Incorrect output for checkNativeTanHalfHalf" +
+                (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+    }
+
+    private void checkNativeTanHalf2Half2() {
+        Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_16, 2, 0xa4d18c7fl, -314, 314);
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+            script.forEach_testNativeTanHalf2Half2(inV, out);
+            verifyResultsNativeTanHalf2Half2(inV, out, false);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanHalf2Half2: " + e.toString());
+        }
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+            scriptRelaxed.forEach_testNativeTanHalf2Half2(inV, out);
+            verifyResultsNativeTanHalf2Half2(inV, out, true);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanHalf2Half2: " + e.toString());
+        }
+    }
+
+    private void verifyResultsNativeTanHalf2Half2(Allocation inV, Allocation out, boolean relaxed) {
+        short[] arrayInV = new short[INPUTSIZE * 2];
+        Arrays.fill(arrayInV, (short) 42);
+        inV.copyTo(arrayInV);
+        short[] arrayOut = new short[INPUTSIZE * 2];
+        Arrays.fill(arrayOut, (short) 42);
+        out.copyTo(arrayOut);
+        StringBuilder message = new StringBuilder();
+        boolean errorFound = false;
+        for (int i = 0; i < INPUTSIZE; i++) {
+            for (int j = 0; j < 2 ; j++) {
+                // Extract the inputs.
+                ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+                args.inV = arrayInV[i * 2 + j];
+                args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+                // Extract the outputs.
+                args.out = arrayOut[i * 2 + j];
+                args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+                // Ask the CoreMathVerifier to validate.
+                Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+                String errorMessage = CoreMathVerifier.verifyNativeTan(args, target);
+                boolean valid = errorMessage == null;
+                if (!valid) {
+                    if (!errorFound) {
+                        errorFound = true;
+                        message.append("Input inV: ");
+                        appendVariableToMessage(message, args.inV);
+                        message.append("\n");
+                        message.append("Output out: ");
+                        appendVariableToMessage(message, args.out);
+                        message.append("\n");
+                        message.append("\n");
+                        message.append("Output out (in double): ");
+                        appendVariableToMessage(message, args.outDouble);
+                        message.append("\n");
+                        message.append(errorMessage);
+                        message.append("Errors at");
+                    }
+                    message.append(" [");
+                    message.append(Integer.toString(i));
+                    message.append(", ");
+                    message.append(Integer.toString(j));
+                    message.append("]");
+                }
+            }
+        }
+        assertFalse("Incorrect output for checkNativeTanHalf2Half2" +
+                (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+    }
+
+    private void checkNativeTanHalf3Half3() {
+        Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_16, 3, 0x3d95173l, -314, 314);
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+            script.forEach_testNativeTanHalf3Half3(inV, out);
+            verifyResultsNativeTanHalf3Half3(inV, out, false);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanHalf3Half3: " + e.toString());
+        }
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+            scriptRelaxed.forEach_testNativeTanHalf3Half3(inV, out);
+            verifyResultsNativeTanHalf3Half3(inV, out, true);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanHalf3Half3: " + e.toString());
+        }
+    }
+
+    private void verifyResultsNativeTanHalf3Half3(Allocation inV, Allocation out, boolean relaxed) {
+        short[] arrayInV = new short[INPUTSIZE * 4];
+        Arrays.fill(arrayInV, (short) 42);
+        inV.copyTo(arrayInV);
+        short[] arrayOut = new short[INPUTSIZE * 4];
+        Arrays.fill(arrayOut, (short) 42);
+        out.copyTo(arrayOut);
+        StringBuilder message = new StringBuilder();
+        boolean errorFound = false;
+        for (int i = 0; i < INPUTSIZE; i++) {
+            for (int j = 0; j < 3 ; j++) {
+                // Extract the inputs.
+                ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+                args.inV = arrayInV[i * 4 + j];
+                args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+                // Extract the outputs.
+                args.out = arrayOut[i * 4 + j];
+                args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+                // Ask the CoreMathVerifier to validate.
+                Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+                String errorMessage = CoreMathVerifier.verifyNativeTan(args, target);
+                boolean valid = errorMessage == null;
+                if (!valid) {
+                    if (!errorFound) {
+                        errorFound = true;
+                        message.append("Input inV: ");
+                        appendVariableToMessage(message, args.inV);
+                        message.append("\n");
+                        message.append("Output out: ");
+                        appendVariableToMessage(message, args.out);
+                        message.append("\n");
+                        message.append("\n");
+                        message.append("Output out (in double): ");
+                        appendVariableToMessage(message, args.outDouble);
+                        message.append("\n");
+                        message.append(errorMessage);
+                        message.append("Errors at");
+                    }
+                    message.append(" [");
+                    message.append(Integer.toString(i));
+                    message.append(", ");
+                    message.append(Integer.toString(j));
+                    message.append("]");
+                }
+            }
+        }
+        assertFalse("Incorrect output for checkNativeTanHalf3Half3" +
+                (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+    }
+
+    private void checkNativeTanHalf4Half4() {
+        Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_16, 4, 0x62e11667l, -314, 314);
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+            script.forEach_testNativeTanHalf4Half4(inV, out);
+            verifyResultsNativeTanHalf4Half4(inV, out, false);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanHalf4Half4: " + e.toString());
+        }
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+            scriptRelaxed.forEach_testNativeTanHalf4Half4(inV, out);
+            verifyResultsNativeTanHalf4Half4(inV, out, true);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanHalf4Half4: " + e.toString());
+        }
+    }
+
+    private void verifyResultsNativeTanHalf4Half4(Allocation inV, Allocation out, boolean relaxed) {
+        short[] arrayInV = new short[INPUTSIZE * 4];
+        Arrays.fill(arrayInV, (short) 42);
+        inV.copyTo(arrayInV);
+        short[] arrayOut = new short[INPUTSIZE * 4];
+        Arrays.fill(arrayOut, (short) 42);
+        out.copyTo(arrayOut);
+        StringBuilder message = new StringBuilder();
+        boolean errorFound = false;
+        for (int i = 0; i < INPUTSIZE; i++) {
+            for (int j = 0; j < 4 ; j++) {
+                // Extract the inputs.
+                ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+                args.inV = arrayInV[i * 4 + j];
+                args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+                // Extract the outputs.
+                args.out = arrayOut[i * 4 + j];
+                args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+                // Ask the CoreMathVerifier to validate.
+                Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+                String errorMessage = CoreMathVerifier.verifyNativeTan(args, target);
+                boolean valid = errorMessage == null;
+                if (!valid) {
+                    if (!errorFound) {
+                        errorFound = true;
+                        message.append("Input inV: ");
+                        appendVariableToMessage(message, args.inV);
+                        message.append("\n");
+                        message.append("Output out: ");
+                        appendVariableToMessage(message, args.out);
+                        message.append("\n");
+                        message.append("\n");
+                        message.append("Output out (in double): ");
+                        appendVariableToMessage(message, args.outDouble);
+                        message.append("\n");
+                        message.append(errorMessage);
+                        message.append("Errors at");
+                    }
+                    message.append(" [");
+                    message.append(Integer.toString(i));
+                    message.append(", ");
+                    message.append(Integer.toString(j));
+                    message.append("]");
+                }
+            }
+        }
+        assertFalse("Incorrect output for checkNativeTanHalf4Half4" +
+                (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+    }
+
     public void testNativeTan() {
         checkNativeTanFloatFloat();
         checkNativeTanFloat2Float2();
         checkNativeTanFloat3Float3();
         checkNativeTanFloat4Float4();
+        checkNativeTanHalfHalf();
+        checkNativeTanHalf2Half2();
+        checkNativeTanHalf3Half3();
+        checkNativeTanHalf4Half4();
     }
 }
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTan.rs b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTan.rs
index cbe930b..f28a852 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTan.rs
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTan.rs
@@ -35,3 +35,19 @@
 float4 __attribute__((kernel)) testNativeTanFloat4Float4(float4 inV) {
     return native_tan(inV);
 }
+
+half __attribute__((kernel)) testNativeTanHalfHalf(half inV) {
+    return native_tan(inV);
+}
+
+half2 __attribute__((kernel)) testNativeTanHalf2Half2(half2 inV) {
+    return native_tan(inV);
+}
+
+half3 __attribute__((kernel)) testNativeTanHalf3Half3(half3 inV) {
+    return native_tan(inV);
+}
+
+half4 __attribute__((kernel)) testNativeTanHalf4Half4(half4 inV) {
+    return native_tan(inV);
+}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTanpi.java b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTanpi.java
index 90afaa9..4104851 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTanpi.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTanpi.java
@@ -318,10 +318,293 @@
                 (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
     }
 
+    public class ArgumentsHalfHalf {
+        public short inV;
+        public double inVDouble;
+        public short out;
+        public double outDouble;
+    }
+
+    private void checkNativeTanpiHalfHalf() {
+        Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_16, 1, 0xa1618990l, -100, 100);
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 1), INPUTSIZE);
+            script.forEach_testNativeTanpiHalfHalf(inV, out);
+            verifyResultsNativeTanpiHalfHalf(inV, out, false);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanpiHalfHalf: " + e.toString());
+        }
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 1), INPUTSIZE);
+            scriptRelaxed.forEach_testNativeTanpiHalfHalf(inV, out);
+            verifyResultsNativeTanpiHalfHalf(inV, out, true);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanpiHalfHalf: " + e.toString());
+        }
+    }
+
+    private void verifyResultsNativeTanpiHalfHalf(Allocation inV, Allocation out, boolean relaxed) {
+        short[] arrayInV = new short[INPUTSIZE * 1];
+        Arrays.fill(arrayInV, (short) 42);
+        inV.copyTo(arrayInV);
+        short[] arrayOut = new short[INPUTSIZE * 1];
+        Arrays.fill(arrayOut, (short) 42);
+        out.copyTo(arrayOut);
+        StringBuilder message = new StringBuilder();
+        boolean errorFound = false;
+        for (int i = 0; i < INPUTSIZE; i++) {
+            for (int j = 0; j < 1 ; j++) {
+                // Extract the inputs.
+                ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+                args.inV = arrayInV[i];
+                args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+                // Extract the outputs.
+                args.out = arrayOut[i * 1 + j];
+                args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+                // Ask the CoreMathVerifier to validate.
+                Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+                String errorMessage = CoreMathVerifier.verifyNativeTanpi(args, target);
+                boolean valid = errorMessage == null;
+                if (!valid) {
+                    if (!errorFound) {
+                        errorFound = true;
+                        message.append("Input inV: ");
+                        appendVariableToMessage(message, args.inV);
+                        message.append("\n");
+                        message.append("Output out: ");
+                        appendVariableToMessage(message, args.out);
+                        message.append("\n");
+                        message.append("\n");
+                        message.append("Output out (in double): ");
+                        appendVariableToMessage(message, args.outDouble);
+                        message.append("\n");
+                        message.append(errorMessage);
+                        message.append("Errors at");
+                    }
+                    message.append(" [");
+                    message.append(Integer.toString(i));
+                    message.append(", ");
+                    message.append(Integer.toString(j));
+                    message.append("]");
+                }
+            }
+        }
+        assertFalse("Incorrect output for checkNativeTanpiHalfHalf" +
+                (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+    }
+
+    private void checkNativeTanpiHalf2Half2() {
+        Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_16, 2, 0x40b19f32l, -100, 100);
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+            script.forEach_testNativeTanpiHalf2Half2(inV, out);
+            verifyResultsNativeTanpiHalf2Half2(inV, out, false);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanpiHalf2Half2: " + e.toString());
+        }
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 2), INPUTSIZE);
+            scriptRelaxed.forEach_testNativeTanpiHalf2Half2(inV, out);
+            verifyResultsNativeTanpiHalf2Half2(inV, out, true);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanpiHalf2Half2: " + e.toString());
+        }
+    }
+
+    private void verifyResultsNativeTanpiHalf2Half2(Allocation inV, Allocation out, boolean relaxed) {
+        short[] arrayInV = new short[INPUTSIZE * 2];
+        Arrays.fill(arrayInV, (short) 42);
+        inV.copyTo(arrayInV);
+        short[] arrayOut = new short[INPUTSIZE * 2];
+        Arrays.fill(arrayOut, (short) 42);
+        out.copyTo(arrayOut);
+        StringBuilder message = new StringBuilder();
+        boolean errorFound = false;
+        for (int i = 0; i < INPUTSIZE; i++) {
+            for (int j = 0; j < 2 ; j++) {
+                // Extract the inputs.
+                ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+                args.inV = arrayInV[i * 2 + j];
+                args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+                // Extract the outputs.
+                args.out = arrayOut[i * 2 + j];
+                args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+                // Ask the CoreMathVerifier to validate.
+                Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+                String errorMessage = CoreMathVerifier.verifyNativeTanpi(args, target);
+                boolean valid = errorMessage == null;
+                if (!valid) {
+                    if (!errorFound) {
+                        errorFound = true;
+                        message.append("Input inV: ");
+                        appendVariableToMessage(message, args.inV);
+                        message.append("\n");
+                        message.append("Output out: ");
+                        appendVariableToMessage(message, args.out);
+                        message.append("\n");
+                        message.append("\n");
+                        message.append("Output out (in double): ");
+                        appendVariableToMessage(message, args.outDouble);
+                        message.append("\n");
+                        message.append(errorMessage);
+                        message.append("Errors at");
+                    }
+                    message.append(" [");
+                    message.append(Integer.toString(i));
+                    message.append(", ");
+                    message.append(Integer.toString(j));
+                    message.append("]");
+                }
+            }
+        }
+        assertFalse("Incorrect output for checkNativeTanpiHalf2Half2" +
+                (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+    }
+
+    private void checkNativeTanpiHalf3Half3() {
+        Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_16, 3, 0x9fb96426l, -100, 100);
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+            script.forEach_testNativeTanpiHalf3Half3(inV, out);
+            verifyResultsNativeTanpiHalf3Half3(inV, out, false);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanpiHalf3Half3: " + e.toString());
+        }
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 3), INPUTSIZE);
+            scriptRelaxed.forEach_testNativeTanpiHalf3Half3(inV, out);
+            verifyResultsNativeTanpiHalf3Half3(inV, out, true);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanpiHalf3Half3: " + e.toString());
+        }
+    }
+
+    private void verifyResultsNativeTanpiHalf3Half3(Allocation inV, Allocation out, boolean relaxed) {
+        short[] arrayInV = new short[INPUTSIZE * 4];
+        Arrays.fill(arrayInV, (short) 42);
+        inV.copyTo(arrayInV);
+        short[] arrayOut = new short[INPUTSIZE * 4];
+        Arrays.fill(arrayOut, (short) 42);
+        out.copyTo(arrayOut);
+        StringBuilder message = new StringBuilder();
+        boolean errorFound = false;
+        for (int i = 0; i < INPUTSIZE; i++) {
+            for (int j = 0; j < 3 ; j++) {
+                // Extract the inputs.
+                ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+                args.inV = arrayInV[i * 4 + j];
+                args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+                // Extract the outputs.
+                args.out = arrayOut[i * 4 + j];
+                args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+                // Ask the CoreMathVerifier to validate.
+                Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+                String errorMessage = CoreMathVerifier.verifyNativeTanpi(args, target);
+                boolean valid = errorMessage == null;
+                if (!valid) {
+                    if (!errorFound) {
+                        errorFound = true;
+                        message.append("Input inV: ");
+                        appendVariableToMessage(message, args.inV);
+                        message.append("\n");
+                        message.append("Output out: ");
+                        appendVariableToMessage(message, args.out);
+                        message.append("\n");
+                        message.append("\n");
+                        message.append("Output out (in double): ");
+                        appendVariableToMessage(message, args.outDouble);
+                        message.append("\n");
+                        message.append(errorMessage);
+                        message.append("Errors at");
+                    }
+                    message.append(" [");
+                    message.append(Integer.toString(i));
+                    message.append(", ");
+                    message.append(Integer.toString(j));
+                    message.append("]");
+                }
+            }
+        }
+        assertFalse("Incorrect output for checkNativeTanpiHalf3Half3" +
+                (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+    }
+
+    private void checkNativeTanpiHalf4Half4() {
+        Allocation inV = createRandomFloatAllocation(mRS, Element.DataType.FLOAT_16, 4, 0xfec1291al, -100, 100);
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+            script.forEach_testNativeTanpiHalf4Half4(inV, out);
+            verifyResultsNativeTanpiHalf4Half4(inV, out, false);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanpiHalf4Half4: " + e.toString());
+        }
+        try {
+            Allocation out = Allocation.createSized(mRS, getElement(mRS, Element.DataType.FLOAT_16, 4), INPUTSIZE);
+            scriptRelaxed.forEach_testNativeTanpiHalf4Half4(inV, out);
+            verifyResultsNativeTanpiHalf4Half4(inV, out, true);
+        } catch (Exception e) {
+            throw new RSRuntimeException("RenderScript. Can't invoke forEach_testNativeTanpiHalf4Half4: " + e.toString());
+        }
+    }
+
+    private void verifyResultsNativeTanpiHalf4Half4(Allocation inV, Allocation out, boolean relaxed) {
+        short[] arrayInV = new short[INPUTSIZE * 4];
+        Arrays.fill(arrayInV, (short) 42);
+        inV.copyTo(arrayInV);
+        short[] arrayOut = new short[INPUTSIZE * 4];
+        Arrays.fill(arrayOut, (short) 42);
+        out.copyTo(arrayOut);
+        StringBuilder message = new StringBuilder();
+        boolean errorFound = false;
+        for (int i = 0; i < INPUTSIZE; i++) {
+            for (int j = 0; j < 4 ; j++) {
+                // Extract the inputs.
+                ArgumentsHalfHalf args = new ArgumentsHalfHalf();
+                args.inV = arrayInV[i * 4 + j];
+                args.inVDouble = Float16Utils.convertFloat16ToDouble(args.inV);
+                // Extract the outputs.
+                args.out = arrayOut[i * 4 + j];
+                args.outDouble = Float16Utils.convertFloat16ToDouble(args.out);
+                // Ask the CoreMathVerifier to validate.
+                Target target = new Target(Target.FunctionType.NATIVE, Target.ReturnType.HALF, relaxed);
+                String errorMessage = CoreMathVerifier.verifyNativeTanpi(args, target);
+                boolean valid = errorMessage == null;
+                if (!valid) {
+                    if (!errorFound) {
+                        errorFound = true;
+                        message.append("Input inV: ");
+                        appendVariableToMessage(message, args.inV);
+                        message.append("\n");
+                        message.append("Output out: ");
+                        appendVariableToMessage(message, args.out);
+                        message.append("\n");
+                        message.append("\n");
+                        message.append("Output out (in double): ");
+                        appendVariableToMessage(message, args.outDouble);
+                        message.append("\n");
+                        message.append(errorMessage);
+                        message.append("Errors at");
+                    }
+                    message.append(" [");
+                    message.append(Integer.toString(i));
+                    message.append(", ");
+                    message.append(Integer.toString(j));
+                    message.append("]");
+                }
+            }
+        }
+        assertFalse("Incorrect output for checkNativeTanpiHalf4Half4" +
+                (relaxed ? "_relaxed" : "") + ":\n" + message.toString(), errorFound);
+    }
+
     public void testNativeTanpi() {
         checkNativeTanpiFloatFloat();
         checkNativeTanpiFloat2Float2();
         checkNativeTanpiFloat3Float3();
         checkNativeTanpiFloat4Float4();
+        checkNativeTanpiHalfHalf();
+        checkNativeTanpiHalf2Half2();
+        checkNativeTanpiHalf3Half3();
+        checkNativeTanpiHalf4Half4();
     }
 }
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTanpi.rs b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTanpi.rs
index 21e0b15..902cda2 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTanpi.rs
+++ b/tests/tests/renderscript/src/android/renderscript/cts/generated/TestNativeTanpi.rs
@@ -35,3 +35,19 @@
 float4 __attribute__((kernel)) testNativeTanpiFloat4Float4(float4 inV) {
     return native_tanpi(inV);
 }
+
+half __attribute__((kernel)) testNativeTanpiHalfHalf(half inV) {
+    return native_tanpi(inV);
+}
+
+half2 __attribute__((kernel)) testNativeTanpiHalf2Half2(half2 inV) {
+    return native_tanpi(inV);
+}
+
+half3 __attribute__((kernel)) testNativeTanpiHalf3Half3(half3 inV) {
+    return native_tanpi(inV);
+}
+
+half4 __attribute__((kernel)) testNativeTanpiHalf4Half4(half4 inV) {
+    return native_tanpi(inV);
+}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/reduce.rs b/tests/tests/renderscript/src/android/renderscript/cts/reduce.rs
index c30cb9c..d731561 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/reduce.rs
+++ b/tests/tests/renderscript/src/android/renderscript/cts/reduce.rs
@@ -375,7 +375,7 @@
 }
 
 static void fz3Combine(int3 *accum, const int3 *accum2) {
-  if (accum->x >= 0) *accum = *accum2;
+  if (accum2->x >= 0) *accum = *accum2;
 }
 
 /////////////////////////////////////////////////////////////////////////
diff --git a/tests/tests/security/Android.mk b/tests/tests/security/Android.mk
index 5bd88be..6d728da 100644
--- a/tests/tests/security/Android.mk
+++ b/tests/tests/security/Android.mk
@@ -51,7 +51,8 @@
 		libsync \
 		libcamera_metadata \
 		libspeexresampler \
-		liblzma
+		liblzma \
+		libstagefright_foundation
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)\
                    src/android/security/cts/activity/ISecureRandomService.aidl
diff --git a/tests/tests/security/jni/Android.mk b/tests/tests/security/jni/Android.mk
index a8f4382..d39ac7e 100644
--- a/tests/tests/security/jni/Android.mk
+++ b/tests/tests/security/jni/Android.mk
@@ -26,23 +26,16 @@
 		android_security_cts_CharDeviceTest.cpp \
 		android_security_cts_KernelSettingsTest.cpp \
 		android_security_cts_LinuxRngTest.cpp \
-		android_security_cts_LoadEffectLibraryTest.cpp \
 		android_security_cts_NativeCodeTest.cpp \
 		android_security_cts_SELinuxTest.cpp \
 		android_security_cts_MMapExecutableTest.cpp \
-		android_security_cts_AudioPolicyBinderTest.cpp \
 		android_security_cts_EncryptionTest.cpp \
-		android_security_cts_AudioFlingerBinderTest.cpp \
-		android_security_cts_AudioEffectBinderTest.cpp \
-		android_security_cts_MediaPlayerInfoLeakTest.cpp \
-		android_security_cts_GraphicBufferInfoLeakTest.cpp
 
 LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) \
 										$(TOP)/frameworks/native/include/media/openmax
 
 LOCAL_SHARED_LIBRARIES := libnativehelper \
 		liblog \
-		libbinder \
 		libutils \
 		libmedia \
 		libselinux \
@@ -67,7 +60,8 @@
 		libsync \
 		libcamera_metadata \
 		libspeexresampler \
-		liblzma
+		liblzma \
+		libstagefright_foundation
 
 LOCAL_C_INCLUDES += ndk/sources/cpufeatures
 LOCAL_STATIC_LIBRARIES := cpufeatures
diff --git a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
index 24c87b1..198baa00 100644
--- a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
+++ b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
@@ -21,15 +21,9 @@
 extern int register_android_security_cts_CharDeviceTest(JNIEnv*);
 extern int register_android_security_cts_LinuxRngTest(JNIEnv*);
 extern int register_android_security_cts_NativeCodeTest(JNIEnv*);
-extern int register_android_security_cts_LoadEffectLibraryTest(JNIEnv*);
 extern int register_android_security_cts_SELinuxTest(JNIEnv*);
 extern int register_android_security_cts_MMapExecutableTest(JNIEnv* env);
-extern int register_android_security_cts_AudioPolicyBinderTest(JNIEnv* env);
-extern int register_android_security_cts_AudioFlingerBinderTest(JNIEnv* env);
 extern int register_android_security_cts_EncryptionTest(JNIEnv* env);
-extern int register_android_security_cts_AudioEffectBinderTest(JNIEnv* env);
-extern int register_android_security_cts_MediaPlayerInfoLeakTest(JNIEnv* env);
-extern int register_android_security_cts_GraphicBufferInfoLeakTest(JNIEnv* env);
 
 jint JNI_OnLoad(JavaVM *vm, void *reserved) {
     JNIEnv *env = NULL;
@@ -50,10 +44,6 @@
         return JNI_ERR;
     }
 
-    if (register_android_security_cts_LoadEffectLibraryTest(env)) {
-        return JNI_ERR;
-    }
-
     if (register_android_security_cts_SELinuxTest(env)) {
         return JNI_ERR;
     }
@@ -66,33 +56,9 @@
         return JNI_ERR;
     }
 
-    if (register_android_security_cts_AudioPolicyBinderTest(env)) {
-        return JNI_ERR;
-    }
-
     if (register_android_security_cts_EncryptionTest(env)) {
         return JNI_ERR;
     }
 
-    if (register_android_security_cts_AudioFlingerBinderTest(env)) {
-        return JNI_ERR;
-    }
-
-    if (register_android_security_cts_AudioEffectBinderTest(env)) {
-        return JNI_ERR;
-    }
-
-    if (register_android_security_cts_MediaPlayerInfoLeakTest(env)) {
-        return JNI_ERR;
-    }
-
-    if (register_android_security_cts_AudioFlingerBinderTest(env)) {
-        return JNI_ERR;
-    }
-
-    if (register_android_security_cts_GraphicBufferInfoLeakTest(env)) {
-        return JNI_ERR;
-    }
-
     return JNI_VERSION_1_4;
 }
diff --git a/tests/tests/security/jni/android_security_cts_AudioEffectBinderTest.cpp b/tests/tests/security/jni/android_security_cts_AudioEffectBinderTest.cpp
deleted file mode 100644
index 6e94fce..0000000
--- a/tests/tests/security/jni/android_security_cts_AudioEffectBinderTest.cpp
+++ /dev/null
@@ -1,161 +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.
- */
-
-#define LOG_TAG "AudioEffectBinderTest-JNI"
-
-#include <jni.h>
-#include <media/AudioEffect.h>
-#include <media/IEffect.h>
-
-using namespace android;
-
-/*
- * Native methods used by
- * cts/tests/tests/security/src/android/security/cts/AudioEffectBinderTest.java
- */
-
-struct EffectClient : public BnEffectClient {
-    EffectClient() { }
-    virtual void controlStatusChanged(bool controlGranted __unused) { }
-    virtual void enableStatusChanged(bool enabled __unused) { }
-    virtual void commandExecuted(uint32_t cmdCode __unused,
-            uint32_t cmdSize __unused,
-            void *pCmdData __unused,
-            uint32_t replySize __unused,
-            void *pReplyData __unused) { }
-};
-
-struct DeathRecipient : public IBinder::DeathRecipient {
-    DeathRecipient() : mDied(false) { }
-    virtual void binderDied(const wp<IBinder>& who __unused) { mDied = true; }
-    bool died() const { return mDied; }
-    bool mDied;
-};
-
-static bool isIEffectCommandSecure(IEffect *effect)
-{
-    // some magic constants here
-    const int COMMAND_SIZE = 1024 + 12; // different than reply size to get different heap frag
-    char cmdData[COMMAND_SIZE];
-    memset(cmdData, 0xde, sizeof(cmdData));
-
-    const int REPLY_DATA_SIZE = 256;
-    char replyData[REPLY_DATA_SIZE];
-    bool secure = true;
-    for (int k = 0; k < 10; ++k) {
-        Parcel data;
-        data.writeInterfaceToken(effect->getInterfaceDescriptor());
-        data.writeInt32(0);  // 0 is EFFECT_CMD_INIT
-        data.writeInt32(sizeof(cmdData));
-        data.write(cmdData, sizeof(cmdData));
-        data.writeInt32(sizeof(replyData));
-
-        Parcel reply;
-        status_t status = effect->asBinder(effect)->transact(3, data, &reply);  // 3 is COMMAND
-        ALOGV("transact status: %d", status);
-        if (status != NO_ERROR) {
-            ALOGW("invalid transaction status %d", status);
-            continue;
-        }
-
-        ALOGV("reply data avail %zu", reply.dataAvail());
-        status = reply.readInt32();
-        ALOGV("reply status %d", status);
-        if (status == NO_ERROR) {
-            continue;
-        }
-
-        int size = reply.readInt32();
-        ALOGV("reply size %d", size);
-        if (size != sizeof(replyData)) { // we expect 0 or full reply data if command failed
-            ALOGW_IF(size != 0, "invalid reply size: %d", size);
-            continue;
-        }
-
-        // Note that if reply.read() returns success, it should completely fill replyData.
-        status = reply.read(replyData, sizeof(replyData));
-        if (status != NO_ERROR) {
-            ALOGW("invalid reply read - ignoring");
-            continue;
-        }
-        unsigned int *out = (unsigned int *)replyData;
-        for (size_t index = 0; index < sizeof(replyData) / sizeof(*out); ++index) {
-            if (out[index] != 0) {
-                secure = false;
-                ALOGI("leaked data = %#08x", out[index]);
-            }
-        }
-    }
-    ALOGI("secure: %s", secure ? "YES" : "NO");
-    return secure;
-}
-
-static jboolean android_security_cts_AudioEffect_test_isCommandSecure()
-{
-    const sp<IAudioFlinger> &audioFlinger = AudioSystem::get_audio_flinger();
-    if (audioFlinger.get() == NULL) {
-        ALOGE("could not get audioflinger");
-        return JNI_FALSE;
-    }
-
-    static const effect_uuid_t EFFECT_UIID_EQUALIZER =  // type
-        { 0x0bed4300, 0xddd6, 0x11db, 0x8f34, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b }};
-    sp<EffectClient> effectClient(new EffectClient());
-    effect_descriptor_t descriptor;
-    memset(&descriptor, 0, sizeof(descriptor));
-    descriptor.type = EFFECT_UIID_EQUALIZER;
-    descriptor.uuid = *EFFECT_UUID_NULL;
-    const int32_t priority = 0;
-    const audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX;
-    const audio_io_handle_t io = AUDIO_IO_HANDLE_NONE;
-    const String16 opPackageName("Exploitable");
-    status_t status;
-    int32_t id;
-    int enabled;
-    sp<IEffect> effect = audioFlinger->createEffect(&descriptor, effectClient,
-            priority, io, sessionId, opPackageName, &status, &id, &enabled);
-    if (effect.get() == NULL || status != NO_ERROR) {
-        ALOGW("could not create effect");
-        return JNI_TRUE;
-    }
-
-    sp<DeathRecipient> deathRecipient(new DeathRecipient());
-    IInterface::asBinder(effect)->linkToDeath(deathRecipient);
-
-    // check exploit
-    if (!isIEffectCommandSecure(effect.get())) {
-        ALOGE("not secure!");
-        return JNI_FALSE;
-    }
-
-    sleep(1); // wait to check death
-    if (deathRecipient->died()) {
-        ALOGE("effect binder died");
-        return JNI_FALSE;
-    }
-    return JNI_TRUE;
-}
-
-int register_android_security_cts_AudioEffectBinderTest(JNIEnv *env)
-{
-    static JNINativeMethod methods[] = {
-        { "native_test_isCommandSecure", "()Z",
-                (void *) android_security_cts_AudioEffect_test_isCommandSecure },
-    };
-
-    jclass clazz = env->FindClass("android/security/cts/AudioEffectBinderTest");
-    return env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0]));
-}
diff --git a/tests/tests/security/jni/android_security_cts_AudioFlingerBinderTest.cpp b/tests/tests/security/jni/android_security_cts_AudioFlingerBinderTest.cpp
deleted file mode 100644
index f4e79e5..0000000
--- a/tests/tests/security/jni/android_security_cts_AudioFlingerBinderTest.cpp
+++ /dev/null
@@ -1,342 +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.
- */
-
-#define LOG_TAG "AudioFlingerBinderTest-JNI"
-
-#include <jni.h>
-#include <binder/IServiceManager.h>
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <media/IAudioFlinger.h>
-#include <media/AudioSystem.h>
-#include <system/audio.h>
-#include <utils/Log.h>
-#include <utils/SystemClock.h>
-
-using namespace android;
-
-/*
- * Native methods used by
- * cts/tests/tests/security/src/android/security/cts/AudioFlingerBinderTest.java
- */
-
-#define TEST_ARRAY_SIZE 10000
-#define MAX_ARRAY_SIZE 1024
-#define TEST_PATTERN 0x55
-
-class MyDeathClient: public IBinder::DeathRecipient
-{
-public:
-    MyDeathClient() :
-        mAfIsDead(false) {
-    }
-
-    bool afIsDead() const { return mAfIsDead; }
-
-    // DeathRecipient
-    virtual void binderDied(const wp<IBinder>& who __unused) { mAfIsDead = true; }
-
-private:
-    bool mAfIsDead;
-};
-
-
-static bool connectAudioFlinger(sp<IAudioFlinger>& af, sp<MyDeathClient> &dr)
-{
-    int64_t startTime = 0;
-    while (af == 0) {
-        sp<IBinder> binder = defaultServiceManager()->checkService(String16("media.audio_flinger"));
-        if (binder == 0) {
-            if (startTime == 0) {
-                startTime = uptimeMillis();
-            } else if ((uptimeMillis()-startTime) > 10000) {
-                ALOGE("timeout while getting audio flinger service");
-                return false;
-            }
-            sleep(1);
-        } else {
-            af = interface_cast<IAudioFlinger>(binder);
-            dr = new MyDeathClient();
-            binder->linkToDeath(dr);
-        }
-    }
-    // Allow binderDied() to be called on MyDeathClient
-    sp<ProcessState> proc(ProcessState::self());
-    ProcessState::self()->startThreadPool();
-    return true;
-}
-
-/*
- * Checks that AudioSystem::setMasterMute() does not crash mediaserver if a duplicated output
- * is opened.
- */
-jboolean android_security_cts_AudioFlinger_test_setMasterMute(JNIEnv* env __unused,
-                                                           jobject thiz __unused)
-{
-    sp<IAudioFlinger> af;
-    sp<MyDeathClient> dr;
-
-    if (!connectAudioFlinger(af, dr)) {
-        return false;
-    }
-
-    // force opening of a duplicating output
-    status_t status = AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
-                                          AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
-                                          "0", "");
-    if (status != NO_ERROR) {
-        return false;
-    }
-
-    bool mute;
-    status = AudioSystem::getMasterMute(&mute);
-    if (status != NO_ERROR) {
-        return false;
-    }
-
-    AudioSystem::setMasterMute(!mute);
-
-    sleep(1);
-
-    // Check that mediaserver did not crash
-    if (dr->afIsDead()) {
-        return false;
-    }
-
-    AudioSystem::setMasterMute(mute);
-
-    AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
-                                          AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
-                                          "0", "");
-
-    AudioSystem::setMasterMute(false);
-
-    return true;
-}
-
-jboolean android_security_cts_AudioFlinger_test_setMasterVolume(JNIEnv* env __unused,
-                                                           jobject thiz __unused)
-{
-    sp<IAudioFlinger> af;
-    sp<MyDeathClient> dr;
-
-    if (!connectAudioFlinger(af, dr)) {
-        return false;
-    }
-
-    // force opening of a duplicating output
-    status_t status = AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
-                                          AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
-                                          "0", "");
-    if (status != NO_ERROR) {
-        return false;
-    }
-
-    float vol;
-    status = AudioSystem::getMasterVolume(&vol);
-    if (status != NO_ERROR) {
-        return false;
-    }
-
-    AudioSystem::setMasterVolume(vol < 0.5 ? 1.0 : 0.0);
-
-    sleep(1);
-
-    // Check that mediaserver did not crash
-    if (dr->afIsDead()) {
-        return false;
-    }
-
-    AudioSystem::setMasterMute(vol);
-
-    AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
-                                          AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
-                                          "0", "");
-
-    return true;
-}
-
-jboolean android_security_cts_AudioFlinger_test_listAudioPorts(JNIEnv* env __unused,
-                                                           jobject thiz __unused)
-{
-    sp<IAudioFlinger> af;
-    sp<MyDeathClient> dr;
-
-    if (!connectAudioFlinger(af, dr)) {
-        return false;
-    }
-
-    unsigned int num_ports = TEST_ARRAY_SIZE;
-    struct audio_port *ports =
-            (struct audio_port *)calloc(TEST_ARRAY_SIZE, sizeof(struct audio_port));
-
-    memset(ports, TEST_PATTERN, TEST_ARRAY_SIZE * sizeof(struct audio_port));
-
-    status_t status = af->listAudioPorts(&num_ports, ports);
-
-    sleep(1);
-
-    // Check that the memory content above the max allowed array size was not changed
-    char *ptr = (char *)(ports + MAX_ARRAY_SIZE);
-    for (size_t i = 0; i < TEST_ARRAY_SIZE - MAX_ARRAY_SIZE; i++) {
-        if (ptr[i * sizeof(struct audio_port)] != TEST_PATTERN) {
-            free(ports);
-            return false;
-        }
-    }
-
-    free(ports);
-
-    // Check that mediaserver did not crash
-    if (dr->afIsDead()) {
-        return false;
-    }
-
-    return true;
-}
-
-jboolean android_security_cts_AudioFlinger_test_listAudioPatches(JNIEnv* env __unused,
-                                                           jobject thiz __unused)
-{
-    sp<IAudioFlinger> af;
-    sp<MyDeathClient> dr;
-
-    if (!connectAudioFlinger(af, dr)) {
-        return false;
-    }
-
-    unsigned int num_patches = TEST_ARRAY_SIZE;
-    struct audio_patch *patches =
-            (struct audio_patch *)calloc(TEST_ARRAY_SIZE, sizeof(struct audio_patch));
-
-    memset(patches, TEST_PATTERN, TEST_ARRAY_SIZE * sizeof(struct audio_patch));
-
-    status_t status = af->listAudioPatches(&num_patches, patches);
-
-    sleep(1);
-
-    // Check that the memory content above the max allowed array size was not changed
-    char *ptr = (char *)(patches + MAX_ARRAY_SIZE);
-    for (size_t i = 0; i < TEST_ARRAY_SIZE - MAX_ARRAY_SIZE; i++) {
-        if (ptr[i * sizeof(struct audio_patch)] != TEST_PATTERN) {
-            free(patches);
-            return false;
-        }
-    }
-
-    free(patches);
-
-    // Check that mediaserver did not crash
-    if (dr->afIsDead()) {
-        return false;
-    }
-
-    return true;
-}
-
-jboolean android_security_cts_AudioFlinger_test_createEffect(JNIEnv* env __unused,
-                                                             jobject thiz __unused)
-{
-    sp<IAudioFlinger> af;
-    sp<MyDeathClient> dr;
-
-    if (!connectAudioFlinger(af, dr)) {
-        return false;
-    }
-
-    for (int j = 0; j < 10; ++j) {
-        Parcel data, reply;
-        data.writeInterfaceToken(af->getInterfaceDescriptor());
-        data.writeInt32((int32_t)j);
-        status_t status = af->asBinder(af)->transact(40, data, &reply); // 40 is CREATE_EFFECT
-        if (status != NO_ERROR) {
-            return false;
-        }
-
-        status = (status_t)reply.readInt32();
-        if (status == NO_ERROR) {
-            continue;
-        }
-
-        int id = reply.readInt32();
-        int enabled = reply.readInt32();
-        sp<IEffect> effect = interface_cast<IEffect>(reply.readStrongBinder());
-        effect_descriptor_t desc;
-        effect_descriptor_t descTarget;
-        memset(&desc, 0, sizeof(effect_descriptor_t));
-        memset(&descTarget, 0, sizeof(effect_descriptor_t));
-        reply.read(&desc, sizeof(effect_descriptor_t));
-        if (id != 0 || enabled != 0 || memcmp(&desc, &descTarget, sizeof(effect_descriptor_t))) {
-            return false;
-        }
-    }
-
-    sleep(1);
-
-    // Check that mediaserver did not crash
-    if (dr->afIsDead()) {
-        return false;
-    }
-
-    return true;
-}
-
-
-#define NUM_ATTEMPTS 5
-
-jboolean android_security_cts_AudioFlinger_test_getInputBufferSize(JNIEnv* env __unused,
-                                                             jobject thiz __unused)
-{
-    sp<IAudioFlinger> af;
-    sp<MyDeathClient> dr;
-
-    if (!connectAudioFlinger(af, dr)) {
-        return false;
-    }
-
-    for (size_t i = 0; i < NUM_ATTEMPTS; i++) {
-        af->getInputBufferSize(0, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO);
-        sleep(1);
-        // Check that mediaserver did not crash
-        if (dr->afIsDead()) {
-            return false;
-        }
-    }
-
-    return true;
-}
-
-static JNINativeMethod gMethods[] = {
-    {  "native_test_setMasterMute", "()Z",
-            (void *) android_security_cts_AudioFlinger_test_setMasterMute },
-    {  "native_test_setMasterVolume", "()Z",
-            (void *) android_security_cts_AudioFlinger_test_setMasterVolume },
-    {  "native_test_listAudioPorts", "()Z",
-            (void *) android_security_cts_AudioFlinger_test_listAudioPorts },
-    {  "native_test_listAudioPatches", "()Z",
-            (void *) android_security_cts_AudioFlinger_test_listAudioPatches },
-    {  "native_test_createEffect", "()Z",
-            (void *) android_security_cts_AudioFlinger_test_createEffect },
-    {  "native_test_getInputBufferSize", "()Z",
-            (void *) android_security_cts_AudioFlinger_test_getInputBufferSize },
-};
-
-int register_android_security_cts_AudioFlingerBinderTest(JNIEnv* env)
-{
-    jclass clazz = env->FindClass("android/security/cts/AudioFlingerBinderTest");
-    return env->RegisterNatives(clazz, gMethods,
-            sizeof(gMethods) / sizeof(JNINativeMethod));
-}
diff --git a/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp b/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp
deleted file mode 100644
index d0a8ec9..0000000
--- a/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "AudioPolicyBinderTest-JNI"
-
-#include <jni.h>
-#include <binder/IServiceManager.h>
-#include <binder/Parcel.h>
-#include <media/IAudioPolicyService.h>
-#include <media/AudioSystem.h>
-#include <system/audio.h>
-#include <utils/Log.h>
-#include <utils/SystemClock.h>
-
-using namespace android;
-
-/*
- * Native methods used by
- * cts/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java
- */
-
-static bool init(sp<IAudioPolicyService>& aps, audio_io_handle_t *output, int *session)
-{
-    aps = 0;
-    if (output != NULL) {
-        *output = AUDIO_IO_HANDLE_NONE;
-    }
-    if (session != NULL) {
-        *session = AUDIO_UNIQUE_ID_ALLOCATE;
-    }
-
-    int64_t startTime = 0;
-    sp<IServiceManager> sm = defaultServiceManager();
-    while (aps == 0) {
-        sp<IBinder> binder = defaultServiceManager()->checkService(String16("media.audio_policy"));
-        if (binder == 0) {
-            if (startTime == 0) {
-                startTime = uptimeMillis();
-            } else if ((uptimeMillis()-startTime) > 10000) {
-                ALOGE("timeout while getting audio policy service");
-                return false;
-            }
-            sleep(1);
-        } else {
-            aps = interface_cast<IAudioPolicyService>(binder);
-        }
-    }
-
-    if (output != NULL) {
-        // get a valid output. Any use case will do.
-        for (int stream = AUDIO_STREAM_MIN; stream < AUDIO_STREAM_CNT; stream++) {
-            *output = AudioSystem::getOutput((audio_stream_type_t)stream);
-            if (*output != AUDIO_IO_HANDLE_NONE) {
-                break;
-            }
-        }
-        if (*output == AUDIO_IO_HANDLE_NONE) {
-            ALOGE("cannot get valid audio output");
-            return false;
-        }
-    }
-    if (session != NULL) {
-        //get a valid session
-        *session = AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
-        if (*session == AUDIO_UNIQUE_ID_ALLOCATE) {
-            ALOGE("cannot get valid audio session");
-            return false;
-        }
-    }
-    return true;
-}
-
-/*
- * Checks that IAudioPolicyService::startOutput() cannot be called with an
- * invalid stream type.
- */
-jboolean android_security_cts_AudioPolicy_test_startOutput(JNIEnv* env __unused,
-                                                           jobject thiz __unused)
-{
-    sp<IAudioPolicyService> aps;
-    audio_io_handle_t output;
-    int session;
-
-    if (!init(aps, &output, &session)) {
-        return false;
-    }
-
-    status_t status = aps->startOutput(output, (audio_stream_type_t)(AUDIO_STREAM_MIN -1),
-                                       (audio_session_t)session);
-    if (status == NO_ERROR) {
-        return false;
-    }
-    status = aps->startOutput(output, (audio_stream_type_t)AUDIO_STREAM_CNT,
-                              (audio_session_t)session);
-    if (status == NO_ERROR) {
-        return false;
-    }
-    return true;
-}
-
-/*
- * Checks that IAudioPolicyService::stopOutput() cannot be called with an
- * invalid stream type.
- */
-jboolean android_security_cts_AudioPolicy_test_stopOutput(JNIEnv* env __unused,
-                                                           jobject thiz __unused)
-{
-    sp<IAudioPolicyService> aps;
-    audio_io_handle_t output;
-    int session;
-
-    if (!init(aps, &output, &session)) {
-        return false;
-    }
-
-    status_t status = aps->stopOutput(output, (audio_stream_type_t)(AUDIO_STREAM_MIN -1),
-                                      (audio_session_t)session);
-    if (status == NO_ERROR) {
-        return false;
-    }
-    status = aps->stopOutput(output, (audio_stream_type_t)AUDIO_STREAM_CNT,
-                             (audio_session_t)session);
-    if (status == NO_ERROR) {
-        return false;
-    }
-    return true;
-}
-
-/*
- * Checks that IAudioPolicyService::isStreamActive() cannot be called with an
- * invalid stream type.
- */
-jboolean android_security_cts_AudioPolicy_test_isStreamActive(JNIEnv* env __unused,
-                                                           jobject thiz __unused)
-{
-    sp<IAudioPolicyService> aps;
-
-    if (!init(aps, NULL, NULL)) {
-        return false;
-    }
-
-    bool status = aps->isStreamActive((audio_stream_type_t)(-1), 0);
-    if (status) {
-        return false;
-    }
-    status = aps->isStreamActive((audio_stream_type_t)AUDIO_STREAM_CNT, 0);
-    if (status) {
-        return false;
-    }
-    return true;
-}
-
-/*
- * Checks that IAudioPolicyService::isStreamActiveRemotely() cannot be called with an
- * invalid stream type.
- * Test with NUM_RANDOM_TESTS random values for stream type.
- */
-jboolean android_security_cts_AudioPolicy_test_isStreamActiveRemotely(JNIEnv* env __unused,
-                                                           jobject thiz __unused)
-{
-    sp<IAudioPolicyService> aps;
-
-    if (!init(aps, NULL, NULL)) {
-        return false;
-    }
-
-    if (aps->isStreamActiveRemotely((audio_stream_type_t)(AUDIO_STREAM_MIN -1), 0)) {
-        return false;
-    }
-
-    if (aps->isStreamActiveRemotely((audio_stream_type_t)AUDIO_STREAM_CNT, 0)) {
-        return false;
-    }
-    return true;
-}
-
-jint android_security_cts_AudioPolicy_test_getStreamVolumeLeak(JNIEnv* env __unused,
-                                                           jobject thiz __unused)
-{
-    sp<IAudioPolicyService> aps;
-
-    if (!init(aps, NULL, NULL)) {
-        return -1;
-    }
-
-    // Keep synchronized with IAudioPolicyService.cpp!
-    enum {
-        GET_STREAM_VOLUME = 17,
-    };
-
-    Parcel data, reply;
-    status_t err;
-    data.writeInterfaceToken(aps->getInterfaceDescriptor());
-    data.writeInt32(-1); // stream type
-    data.writeInt32(-1); // device
-    IInterface::asBinder(aps)->transact(GET_STREAM_VOLUME, data, &reply);
-    int index = reply.readInt32();
-    err = reply.readInt32();
-
-    return index;
-}
-
-jboolean android_security_cts_AudioPolicy_test_startAudioSource(JNIEnv* env __unused,
-                                                                jobject thiz __unused)
-{
-    sp<IAudioPolicyService> aps;
-
-    if (!init(aps, NULL, NULL)) {
-        return false;
-    }
-
-    // Keep synchronized with IAudioPolicyService.cpp!
-    enum {
-        START_AUDIO_SOURCE = 41,
-    };
-
-    for (int i = 0; i < 10; ++i) {
-        Parcel data, reply;
-        data.writeInterfaceToken(aps->getInterfaceDescriptor());
-        data.writeInt32(-i);
-        IInterface::asBinder(aps)->transact(START_AUDIO_SOURCE, data, &reply);
-        status_t err = (status_t)reply.readInt32();
-        if (err == NO_ERROR) {
-            continue;
-        }
-        audio_io_handle_t handle = (audio_io_handle_t)reply.readInt32();
-        if (handle != 0) {
-            return false;
-        }
-    }
-
-    return true;
-}
-
-static JNINativeMethod gMethods[] = {
-    {  "native_test_startOutput", "()Z",
-            (void *) android_security_cts_AudioPolicy_test_startOutput },
-    {  "native_test_stopOutput", "()Z",
-                (void *) android_security_cts_AudioPolicy_test_stopOutput },
-    {  "native_test_isStreamActive", "()Z",
-                (void *) android_security_cts_AudioPolicy_test_isStreamActive },
-    {  "native_test_isStreamActiveRemotely", "()Z",
-                (void *) android_security_cts_AudioPolicy_test_isStreamActiveRemotely },
-    {  "native_test_getStreamVolumeLeak", "()I",
-                (void *) android_security_cts_AudioPolicy_test_getStreamVolumeLeak },
-    {  "native_test_startAudioSource", "()Z",
-                (void *) android_security_cts_AudioPolicy_test_startAudioSource },
-};
-
-int register_android_security_cts_AudioPolicyBinderTest(JNIEnv* env)
-{
-    jclass clazz = env->FindClass("android/security/cts/AudioPolicyBinderTest");
-    return env->RegisterNatives(clazz, gMethods,
-            sizeof(gMethods) / sizeof(JNINativeMethod));
-}
diff --git a/tests/tests/security/jni/android_security_cts_GraphicBufferInfoLeakTest.cpp b/tests/tests/security/jni/android_security_cts_GraphicBufferInfoLeakTest.cpp
deleted file mode 100644
index d0cd347..0000000
--- a/tests/tests/security/jni/android_security_cts_GraphicBufferInfoLeakTest.cpp
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "GraphicBufferInfoLeakTest-JNI"
-
-#include <jni.h>
-#include <JNIHelp.h>
-
-#include <binder/Parcel.h>
-#include <binder/IServiceManager.h>
-
-#include <gui/IGraphicBufferProducer.h>
-#include <gui/IGraphicBufferConsumer.h>
-#include <media/IMediaPlayerService.h>
-#include <media/IMediaRecorder.h>
-#include <media/IOMX.h>
-#include <media/stagefright/MediaErrors.h>
-
-#include <sys/stat.h>
-#include <fcntl.h>
-
-using namespace android;
-
-static sp<IMediaPlayerService> getMediaPlayerService()
-{
-   sp<IServiceManager> sm = defaultServiceManager();
-   sp<IBinder> mediaPlayerService = sm->checkService(String16("media.player"));
-
-   sp<IMediaPlayerService> iMPService = IMediaPlayerService::asInterface(mediaPlayerService);
-   return iMPService;
-}
-
-jint android_security_cts_GraphicBuffer_test_attachBufferInfoLeak(JNIEnv* env,
-                                                           jobject thiz __unused)
-{
-    sp<IMediaPlayerService> iMPService = getMediaPlayerService();
-
-    // get IOMX
-    // Keep synchronized with IMediaPlayerService.cpp!
-    enum {
-        GET_OMX = 4,
-    };
-
-    status_t  err;
-    Parcel data, reply;
-    data.writeInterfaceToken(iMPService->getInterfaceDescriptor());
-    err = IMediaPlayerService::asBinder(iMPService)->transact(GET_OMX, data, &reply);
-    if (err != NO_ERROR) {
-        jniThrowException(env, "java/lang/RuntimeException", "GET_OMX failed");
-    }
-
-    // get IGraphicBufferConsumer
-    sp<IGraphicBufferProducer> iBufferProducer;
-    sp<IGraphicBufferConsumer> iBufferConsumer;
-    sp<IOMX> iOmx = interface_cast<IOMX>(reply.readStrongBinder());
-    err = iOmx->createPersistentInputSurface(&iBufferProducer, &iBufferConsumer);
-    if (err != NO_ERROR) {
-        jniThrowException(env, "java/lang/RuntimeException", "createPersistentInputSurface failed");
-        return err;
-    }
-
-    // Keep synchronized with IGraphicBufferConsumer.cpp!
-    enum {
-        ATTACH_BUFFER = 3,
-    };
-
-    for (;;) {
-        Parcel data2, reply2;
-        data2.writeInterfaceToken(iBufferConsumer->getInterfaceDescriptor());
-        err = IGraphicBufferConsumer::asBinder(iBufferConsumer)->transact(ATTACH_BUFFER, data2, &reply2);
-        if (err != NO_ERROR) {
-            jniThrowException(env, "java/lang/RuntimeException", "ATTACH_BUFFER failed");
-        }
-
-        int32_t slot = reply2.readInt32();
-        status_t result = reply2.readInt32();
-        ALOGV("slot %d", slot);
-        if (result != 0) {
-            // only check for leaked data in error case
-            return slot;
-        }
-    }
-}
-
-jint android_security_cts_GraphicBuffer_test_queueBufferInfoLeak(JNIEnv* env,
-                                                           jobject thiz __unused)
-{
-    sp<IMediaPlayerService> iMPService = getMediaPlayerService();
-    sp<IMediaRecorder> recorder = iMPService->createMediaRecorder(String16("GraphicBufferInfoLeakTest"));
-
-    const char *fileName = "/dev/null";
-    int fd = open(fileName, O_RDWR | O_CREAT, 0744);
-    if (fd < 0) {
-        jniThrowException(env, "java/lang/RuntimeException", "open output failed");
-        return fd;
-    }
-
-    recorder->setVideoSource(2);
-    recorder->setOutputFile(fd, 0, 0);
-    recorder->setOutputFormat(0);
-    recorder->init();
-    recorder->prepare();
-    recorder->start();
-
-    //get IGraphicBufferProducer
-    sp<IGraphicBufferProducer> iGBP = recorder->querySurfaceMediaSource();
-    ALOGV("fd %d, Get iGBP instance, 0x%08x\n", fd, iGBP.get());
-
-    // Keep synchronized with IGraphicBufferProducer.cpp!
-    enum {
-        QUEUE_BUFFER = 7,
-    };
-
-    for (;;) {
-        status_t err;
-        Parcel data, reply;
-        data.writeInterfaceToken(iGBP->getInterfaceDescriptor());
-        data.writeInt32(-1);
-        err = IGraphicBufferProducer::asBinder(iGBP)->transact(QUEUE_BUFFER, data, &reply);
-        if (err != NO_ERROR) {
-            recorder->stop();
-            recorder->release();
-            jniThrowException(env, "java/lang/RuntimeException", "QUEUE_BUFFER failed");
-            return err;
-        }
-
-        size_t len = reply.dataAvail();
-        int32_t result; // last sizeof(int32_t) bytes of Parcel
-        ALOGV("dataAvail = %zu\n", len);
-        if (len < sizeof(result)) {
-            // must contain result
-            recorder->stop();
-            recorder->release();
-            jniThrowException(env, "java/lang/RuntimeException", "reply malformed");
-            return ERROR_MALFORMED;
-        }
-
-        uint8_t *reply_data = (uint8_t *)reply.data();
-        memcpy(&result, reply_data + len - sizeof(result), sizeof(result));
-        if (result == NO_ERROR) {
-            // only check for leaked data in error case
-            continue;
-        }
-
-        uint8_t leaked_data = 0;
-        for (size_t i = 0; i < len - sizeof(result); ++i) {
-            ALOGV("IGraphicBufferProducer_InfoLeak reply_data[%d] = 0x%08x", i, reply_data[i]);
-            if (reply_data[i]) {
-                leaked_data = reply_data[i];
-                break;
-            }
-        }
-
-        recorder->stop();
-        recorder->release();
-        return leaked_data;
-    }
-}
-
-static JNINativeMethod gMethods[] = {
-    {  "native_test_attachBufferInfoLeak", "()I",
-            (void *) android_security_cts_GraphicBuffer_test_attachBufferInfoLeak },
-    {  "native_test_queueBufferInfoLeak", "()I",
-            (void *) android_security_cts_GraphicBuffer_test_queueBufferInfoLeak },
-};
-
-int register_android_security_cts_GraphicBufferInfoLeakTest(JNIEnv* env)
-{
-    jclass clazz = env->FindClass("android/security/cts/GraphicBufferInfoLeakTest");
-    return env->RegisterNatives(clazz, gMethods,
-            sizeof(gMethods) / sizeof(JNINativeMethod));
-}
diff --git a/tests/tests/security/jni/android_security_cts_LoadEffectLibraryTest.cpp b/tests/tests/security/jni/android_security_cts_LoadEffectLibraryTest.cpp
deleted file mode 100644
index 6e0f6e1..0000000
--- a/tests/tests/security/jni/android_security_cts_LoadEffectLibraryTest.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <jni.h>
-#include <binder/IServiceManager.h>
-#include <media/IAudioFlinger.h>
-#include <media/AudioEffect.h>
-
-
-using namespace android;
-
-
-/*
- * Native method used by
- * cts/tests/tests/security/src/android/security/cts/LoadEffectLibraryTest.java
- *
- * Checks that no IAudioFlinger binder transaction manages to load an effect library
- * as LOAD_EFFECT_LIBRARY did in gingerbread.
- */
-
-jboolean android_security_cts_LoadEffectLibraryTest_doLoadLibraryTest(JNIEnv* env, jobject thiz)
-{
-    sp<IServiceManager> sm = defaultServiceManager();
-    if (sm == 0) {
-        return false;
-    }
-
-    sp<IBinder> binder = sm->getService(String16("media.audio_flinger"));
-    if (binder == 0) {
-        return false;
-    }
-
-    Parcel data, reply;
-    sp<IAudioFlinger> af = interface_cast<IAudioFlinger>(binder);
-
-    data.writeInterfaceToken(af->getInterfaceDescriptor());
-    // test library path defined in cts/tests/tests/security/testeffect/Android.mk
-    data.writeCString("/system/lib/soundfx/libctstesteffect.so");
-
-    // test 100 IAudioFlinger binder transaction values and check that none corresponds
-    // to LOAD_EFFECT_LIBRARY and successfully loads our test library
-    for (uint32_t i = IBinder::FIRST_CALL_TRANSACTION;
-            i < IBinder::FIRST_CALL_TRANSACTION + 100;
-            i++) {
-        status_t status = binder->transact(i, data, &reply);
-        if (status != NO_ERROR) {
-            continue;
-        }
-        status = reply.readInt32();
-        if (status != NO_ERROR) {
-            continue;
-        }
-
-        // Effect UUID defined in cts/tests/tests/security/testeffect/CTSTestEffect.cpp
-        effect_uuid_t uuid =
-                    {0xff93e360, 0x0c3c, 0x11e3, 0x8a97, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
-        effect_descriptor_t desc;
-
-        status = AudioEffect::getEffectDescriptor(&uuid, &desc);
-        if (status == NO_ERROR) {
-            return false;
-        }
-    }
-    return true;
-}
-
-static JNINativeMethod gMethods[] = {
-    {  "doLoadLibraryTest", "()Z",
-            (void *) android_security_cts_LoadEffectLibraryTest_doLoadLibraryTest },
-};
-
-int register_android_security_cts_LoadEffectLibraryTest(JNIEnv* env)
-{
-    jclass clazz = env->FindClass("android/security/cts/LoadEffectLibraryTest");
-    return env->RegisterNatives(clazz, gMethods,
-            sizeof(gMethods) / sizeof(JNINativeMethod));
-}
diff --git a/tests/tests/security/jni/android_security_cts_MediaPlayerInfoLeakTest.cpp b/tests/tests/security/jni/android_security_cts_MediaPlayerInfoLeakTest.cpp
deleted file mode 100644
index 0c61f25..0000000
--- a/tests/tests/security/jni/android_security_cts_MediaPlayerInfoLeakTest.cpp
+++ /dev/null
@@ -1,105 +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.
- */
-
-#define LOG_TAG "MediaPlayerInfoLeakTest-JNI"
-
-#include <jni.h>
-
-#include <binder/Parcel.h>
-#include <binder/IServiceManager.h>
-
-#include <media/IMediaPlayer.h>
-#include <media/IMediaPlayerService.h>
-#include <media/IMediaPlayerClient.h>
-
-#include <sys/stat.h>
-
-using namespace android;
-
-static status_t connectMediaPlayer(sp<IMediaPlayer>& iMP)
-{
-   sp<IServiceManager> sm = defaultServiceManager();
-   sp<IBinder> mediaPlayerService = sm->checkService(String16("media.player"));
-
-   sp<IMediaPlayerService> iMPService = IMediaPlayerService::asInterface(mediaPlayerService);
-   sp<IMediaPlayerClient> client;
-   Parcel data, reply;
-   int dummyAudioSessionId = 1;
-   data.writeInterfaceToken(iMPService->getInterfaceDescriptor());
-   data.writeStrongBinder(IInterface::asBinder(client));
-   data.writeInt32(dummyAudioSessionId);
-
-   // Keep synchronized with IMediaPlayerService.cpp!
-    enum {
-        CREATE = IBinder::FIRST_CALL_TRANSACTION,
-    };
-   status_t err = IInterface::asBinder(iMPService)->transact(CREATE, data, &reply);
-   if (err == NO_ERROR) {
-       iMP = interface_cast<IMediaPlayer>(reply.readStrongBinder());
-   }
-   return err;
-}
-
-int testMediaPlayerInfoLeak(int command)
-{
-    sp<IMediaPlayer> iMP;
-    if (NO_ERROR != connectMediaPlayer(iMP)) {
-        return false;
-    }
-
-
-    Parcel data, reply;
-    data.writeInterfaceToken(iMP->getInterfaceDescriptor());
-    IInterface::asBinder(iMP)->transact(command, data, &reply);
-
-    int leak = reply.readInt32();
-    status_t err = reply.readInt32();
-    return  leak;
-}
-
-jint android_security_cts_MediaPlayer_test_getCurrentPositionLeak(JNIEnv* env __unused,
-                                                           jobject thiz __unused)
-{
-  // Keep synchronized with IMediaPlayer.cpp!
-  enum {
-      GET_CURRENT_POSITION = 16,
-  };
-  return testMediaPlayerInfoLeak(GET_CURRENT_POSITION);
-}
-
-jint android_security_cts_MediaPlayer_test_getDurationLeak(JNIEnv* env __unused,
-                                                           jobject thiz __unused)
-{
-  // Keep synchronized with IMediaPlayer.cpp!
-  enum {
-      GET_DURATION = 17,
-  };
-  return testMediaPlayerInfoLeak(GET_DURATION);
-}
-
-static JNINativeMethod gMethods[] = {
-    {  "native_test_getCurrentPositionLeak", "()I",
-            (void *) android_security_cts_MediaPlayer_test_getCurrentPositionLeak },
-    {  "native_test_getDurationLeak", "()I",
-            (void *) android_security_cts_MediaPlayer_test_getDurationLeak },
-};
-
-int register_android_security_cts_MediaPlayerInfoLeakTest(JNIEnv* env)
-{
-    jclass clazz = env->FindClass("android/security/cts/MediaPlayerInfoLeakTest");
-    return env->RegisterNatives(clazz, gMethods,
-            sizeof(gMethods) / sizeof(JNINativeMethod));
-}
diff --git a/tests/tests/security/jni/android_security_cts_SELinuxTest.cpp b/tests/tests/security/jni/android_security_cts_SELinuxTest.cpp
index a68bfb6..8f164bc 100644
--- a/tests/tests/security/jni/android_security_cts_SELinuxTest.cpp
+++ b/tests/tests/security/jni/android_security_cts_SELinuxTest.cpp
@@ -29,50 +29,6 @@
 typedef UniquePtr<char[], SecurityContext_Delete> Unique_SecurityContext;
 
 /*
- * Function: checkSELinuxAccess
- * Purpose: Check permissions between two security contexts.
- * Parameters: subjectContextStr: subject security context as a string
- *             objectContextStr: object security context as a string
- *             objectClassStr: object's security class name as a string
- *             permissionStr: permission name as a string
- * Returns: boolean: (true) if permission was granted, (false) otherwise
- * Exceptions: NullPointerException if any argument is NULL
- */
-static jboolean android_security_cts_SELinuxTest_checkSELinuxAccess(JNIEnv *env, jobject, jstring subjectContextStr,
-        jstring objectContextStr, jstring objectClassStr, jstring permissionStr, jstring auxStr) {
-    if (subjectContextStr == NULL || objectContextStr == NULL || objectClassStr == NULL
-            || permissionStr == NULL || auxStr == NULL) {
-        jniThrowNullPointerException(env, NULL);
-        return false;
-    }
-
-    ScopedUtfChars subjectContext(env, subjectContextStr);
-    ScopedUtfChars objectContext(env, objectContextStr);
-    ScopedUtfChars objectClass(env, objectClassStr);
-    ScopedUtfChars permission(env, permissionStr);
-    ScopedUtfChars aux(env, auxStr);
-
-    char *tmp1 = const_cast<char *>(subjectContext.c_str());
-    char *tmp2 = const_cast<char *>(objectContext.c_str());
-    char *tmp3 = const_cast<char *>(aux.c_str());
-    int accessGranted = selinux_check_access(tmp1, tmp2, objectClass.c_str(), permission.c_str(), tmp3);
-    return (accessGranted == 0) ? true : false;
-}
-
-static jboolean android_security_cts_SELinuxTest_checkSELinuxContext(JNIEnv *env, jobject, jstring contextStr) {
-    if (contextStr == NULL) {
-        jniThrowNullPointerException(env, NULL);
-        return false;
-    }
-
-    ScopedUtfChars context(env, contextStr);
-
-    char *tmp = const_cast<char *>(context.c_str());
-    int validContext = security_check_context(tmp);
-    return (validContext == 0) ? true : false;
-}
-
-/*
  * Function: getFileContext
  * Purpose: retrieves the context associated with the given path in the file system
  * Parameters:
@@ -101,26 +57,13 @@
 }
 
 static JNINativeMethod gMethods[] = {
-    {  "checkSELinuxAccess", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z",
-            (void *) android_security_cts_SELinuxTest_checkSELinuxAccess },
-    {  "checkSELinuxContext", "(Ljava/lang/String;)Z",
-            (void *) android_security_cts_SELinuxTest_checkSELinuxContext },
     { "getFileContext", "(Ljava/lang/String;)Ljava/lang/String;",
             (void*) getFileContext },
 };
 
-static int log_callback(int type __attribute__((unused)), const char *fmt __attribute__((unused)), ...)
-{
-    /* do nothing - silence the avc denials */
-    return 0;
-}
-
 int register_android_security_cts_SELinuxTest(JNIEnv* env)
 {
     jclass clazz = env->FindClass("android/security/cts/SELinuxTest");
-    union selinux_callback cb;
-    cb.func_log = log_callback;
-    selinux_set_callback(SELINUX_CB_LOG, cb);
 
     return env->RegisterNatives(clazz, gMethods,
             sizeof(gMethods) / sizeof(JNINativeMethod));
diff --git a/tests/tests/security/src/android/security/cts/AudioEffectBinderTest.java b/tests/tests/security/src/android/security/cts/AudioEffectBinderTest.java
deleted file mode 100644
index 20d9615..0000000
--- a/tests/tests/security/src/android/security/cts/AudioEffectBinderTest.java
+++ /dev/null
@@ -1,56 +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.security.cts;
-
-import android.media.audiofx.AudioEffect;
-
-import java.util.UUID;
-
-import junit.framework.TestCase;
-
-public class AudioEffectBinderTest extends TestCase {
-
-    static {
-        System.loadLibrary("ctssecurity_jni");
-    }
-
-    /**
-     * Checks that IEffect::command() cannot leak data.
-     */
-    public void test_isCommandSecure() throws Exception {
-        if (isEffectTypeAvailable(AudioEffect.EFFECT_TYPE_EQUALIZER)) {
-            assertTrue(native_test_isCommandSecure());
-        }
-    }
-
-    /* see AudioEffect.isEffectTypeAvailable(), implements hidden function */
-    private static boolean isEffectTypeAvailable(UUID type) {
-        AudioEffect.Descriptor[] desc = AudioEffect.queryEffects();
-        if (desc == null) {
-            return false;
-        }
-
-        for (int i = 0; i < desc.length; i++) {
-            if (desc[i].type.equals(type)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private static native boolean native_test_isCommandSecure();
-}
diff --git a/tests/tests/security/src/android/security/cts/AudioFlingerBinderTest.java b/tests/tests/security/src/android/security/cts/AudioFlingerBinderTest.java
deleted file mode 100644
index e84d851..0000000
--- a/tests/tests/security/src/android/security/cts/AudioFlingerBinderTest.java
+++ /dev/null
@@ -1,80 +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.security.cts;
-
-import junit.framework.TestCase;
-
-public class AudioFlingerBinderTest extends TestCase {
-
-    static {
-        System.loadLibrary("ctssecurity_jni");
-    }
-
-    /**
-     * Checks that AudioSystem::setMasterMute() does not crash mediaserver if a duplicated output
-     * is opened.
-     */
-    public void test_setMasterMute() throws Exception {
-        assertTrue(native_test_setMasterMute());
-    }
-
-    /**
-     * Checks that AudioSystem::setMasterVolume() does not crash mediaserver if a duplicated output
-     * is opened.
-     */
-    public void test_setMasterVolume() throws Exception {
-        assertTrue(native_test_setMasterVolume());
-    }
-
-    /**
-     * Checks that IAudioFlinger::listAudioPorts() does not cause a memory overflow when passed a
-     * large number of ports.
-     */
-    public void test_listAudioPorts() throws Exception {
-        assertTrue(native_test_listAudioPorts());
-    }
-
-    /**
-     * Checks that IAudioFlinger::listAudioPatches() does not cause a memory overflow when passed a
-     * large number of ports.
-     */
-    public void test_listAudioPatches() throws Exception {
-        assertTrue(native_test_listAudioPatches());
-    }
-
-    /**
-     * Checks that IAudioFlinger::createEffect() does not leak information on the server side.
-     */
-    public void test_createEffect() throws Exception {
-        assertTrue(native_test_createEffect());
-    }
-
-    /**
-     * Checks that passing a sample rate of 0 to IAudioFlinger::getInputBufferSize()
-     * does not cause a crash in audioserver.
-     */
-    public void test_getInputBufferSize() throws Exception {
-        assertTrue(native_test_getInputBufferSize());
-    }
-
-    private static native boolean native_test_setMasterMute();
-    private static native boolean native_test_setMasterVolume();
-    private static native boolean native_test_listAudioPorts();
-    private static native boolean native_test_listAudioPatches();
-    private static native boolean native_test_createEffect();
-    private static native boolean native_test_getInputBufferSize();
-}
diff --git a/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java b/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java
deleted file mode 100644
index 82346a1..0000000
--- a/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-import junit.framework.TestCase;
-
-public class AudioPolicyBinderTest extends TestCase {
-
-    static {
-        System.loadLibrary("ctssecurity_jni");
-    }
-
-    /**
-     * Checks that IAudioPolicyService::startOutput() cannot be called with an
-     * invalid stream type.
-     */
-    public void test_startOutput() throws Exception {
-        assertTrue(native_test_startOutput());
-    }
-
-    /**
-     * Checks that IAudioPolicyService::stopOutput() cannot be called with an
-     * invalid stream type.
-     */
-    public void test_stopOutput() throws Exception {
-        assertTrue(native_test_stopOutput());
-    }
-
-    /**
-     * Checks that IAudioPolicyService::isStreamActive() cannot be called with an
-     * invalid stream type.
-     */
-    public void test_isStreamActive() throws Exception {
-        assertTrue(native_test_isStreamActive());
-    }
-
-    /**
-     * Checks that IAudioPolicyService::isStreamActiveRemotely() cannot be called with an
-     * invalid stream type.
-     */
-    public void test_isStreamActiveRemotely() throws Exception {
-        assertTrue(native_test_isStreamActiveRemotely());
-    }
-
-    /**
-     * Checks that IAudioPolicyService::getStreamVolumeIndex() does not leak information
-     * when called with an invalid stream/device type.
-     */
-    public void test_getStreamVolumeLeak() throws Exception {
-        int volume = native_test_getStreamVolumeLeak();
-        assertTrue(String.format("Leaked volume 0x%08X", volume), volume == 0);
-    }
-
-    /**
-     * Checks that IAudioPolicyService::startAudioSource() cannot leak information from
-     * server side.
-     */
-    public void test_startAudioSource() throws Exception {
-        assertTrue(native_test_startAudioSource());
-    }
-
-    private static native boolean native_test_startOutput();
-    private static native boolean native_test_stopOutput();
-    private static native boolean native_test_isStreamActive();
-    private static native boolean native_test_isStreamActiveRemotely();
-    private static native int native_test_getStreamVolumeLeak();
-    private static native boolean native_test_startAudioSource();
-}
diff --git a/tests/tests/security/src/android/security/cts/CertificateTest.java b/tests/tests/security/src/android/security/cts/CertificateTest.java
index 3db7aca..5d2a04f 100644
--- a/tests/tests/security/src/android/security/cts/CertificateTest.java
+++ b/tests/tests/security/src/android/security/cts/CertificateTest.java
@@ -16,19 +16,13 @@
 
 package android.security.cts;
 
-import android.content.res.AssetManager;
-import android.test.InstrumentationTestCase;
-
-import java.io.File;
 import java.io.IOException;
-import java.io.InputStream;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.util.Arrays;
 import java.util.Collections;
@@ -36,7 +30,9 @@
 import java.util.List;
 import java.util.Set;
 
-public class CertificateTest extends InstrumentationTestCase {
+import junit.framework.TestCase;
+
+public class CertificateTest extends TestCase {
 
     public void testNoRemovedCertificates() throws Exception {
         Set<String> expectedCertificates = new HashSet<String>(
@@ -50,55 +46,25 @@
      * If you fail CTS as a result of adding a root CA that is not part of the Android root CA
      * store, please see the following.
      *
-     * First, this test exists because adding untrustworthy root CAs to a device has a very
-     * significant security impact. In the worst case, adding a rogue CA can permanently compromise
-     * the confidentiality and integrity of your users' network traffic. Because of this risk,
-     * adding new certificates should be done sparingly and as a last resort -- never as a first
-     * response or short term fix. Before attempting to modify this test, please consider whether
-     * adding a new certificate authority is in your users' best interests.
+     * <p>This test exists because adding root CAs to a device has a very significant security
+     * impact. Whoever has access to the signing keys of that CA can compromise secure network
+     * traffic from affected Android devices, putting users at risk.
      *
-     * Second, because the addition of a new root CA by an OEM can have such dire consequences for
-     * so many people it is imperative that it be done transparently and in the open. Any request to
-     * modify the certificate list used by this test must have a corresponding change in AOSP
-     * (one certificate per change) authored by the OEM in question and including:
+     * <p>If you have a CA certificate which needs to be trusted by a particular app/service,
+     * ask the developer of the app/service to modify it to trust this CA (e.g., using Network
+     * Security Config feature). This avoids compromising the security of network traffic of other
+     * apps on the device.
      *
-     *     - the certificate in question:
-     *       - The certificate must be in a file under
-     *         cts/tests/tests/security/assets/oem_cacerts, in PEM (Privacy-enhanced Electronic
-     *         Mail) format, with the textual representation of the certificate following the PEM
-     *         section.
-     *       - The file name must be in the format of <hash>.<n> where "hash" is the subject hash
-     *         produced by:
-     *           openssl x509 -in cert_file -subject_hash -noout
-     *         and the "n" is a unique integer identifier starting at 0 to deal with collisions.
-     *         See OpenSSL's c_rehash manpage for details.
-     *       - cts/tests/tests/security/tools/format_cert.sh helps meet the above requirements.
+     * <p>If you have a CA certificate that you believe should be present on all Android devices,
+     * please file a public bug at https://code.google.com/p/android/issues/entry.
      *
-     *     - information about who created and maintains both the certificate and the corresponding
-     *       keypair.
-     *
-     *     - information about what the certificate is to be used for and why the certificate is
-     *       appropriate for inclusion.
-     *
-     *     - a statement from the OEM indicating that they have sufficient confidence in the
-     *       security of the key, the security practices of the issuer, and the validity of the
-     *       intended use that they believe adding the certificate is not detrimental to the
-     *       security of the user.
-     *
-     * Finally, please note that this is not the usual process for adding root CAs to Android. If
-     * you have a certificate that you believe should be present on all Android devices, please file
-     * a public bug at https://code.google.com/p/android/issues/entry or http://b.android.com to
-     * seek resolution.
-     *
-     * For questions, comments, and code reviews please contact security@android.com.
+     * <p>For questions, comments, and code reviews please contact security@android.com.
      */
     public void testNoAddedCertificates() throws Exception {
-        Set<String> oemWhitelistedCertificates = getOemWhitelistedCertificates();
         Set<String> expectedCertificates = new HashSet<String>(
                 Arrays.asList(CertificateData.CERTIFICATE_DATA));
         Set<String> deviceCertificates = getDeviceCertificates();
         deviceCertificates.removeAll(expectedCertificates);
-        deviceCertificates.removeAll(oemWhitelistedCertificates);
         assertEquals("Unknown CA certificates", Collections.EMPTY_SET, deviceCertificates);
     }
 
@@ -132,30 +98,6 @@
         return certificates;
     }
 
-    private static final String ASSETS_DIR_OEM_CERTS = "oem_cacerts";
-
-    private Set<String> getOemWhitelistedCertificates() throws Exception {
-        Set<String> certificates = new HashSet<String>();
-        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
-        AssetManager assetManager = getInstrumentation().getContext().getAssets();
-        for (String path : assetManager.list(ASSETS_DIR_OEM_CERTS)) {
-            File certAssetFile = new File(ASSETS_DIR_OEM_CERTS, path);
-            InputStream in = null;
-            try {
-                in = assetManager.open(certAssetFile.toString());
-                X509Certificate certificate = (X509Certificate) certFactory.generateCertificate(in);
-                certificates.add(getFingerprint(certificate));
-            } catch (Exception e) {
-                throw new Exception("Failed to load certificate from asset: " + certAssetFile, e);
-            } finally {
-                if (in != null) {
-                    in.close();
-                }
-            }
-        }
-        return certificates;
-    }
-
     private String getFingerprint(X509Certificate certificate) throws CertificateEncodingException,
             NoSuchAlgorithmException {
         MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
diff --git a/tests/tests/security/src/android/security/cts/GraphicBufferInfoLeakTest.java b/tests/tests/security/src/android/security/cts/GraphicBufferInfoLeakTest.java
deleted file mode 100644
index 6005e37..0000000
--- a/tests/tests/security/src/android/security/cts/GraphicBufferInfoLeakTest.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-import junit.framework.TestCase;
-
-public class GraphicBufferInfoLeakTest extends TestCase {
-
-    static {
-        System.loadLibrary("ctssecurity_jni");
-    }
-
-    /**
-     * Check that IGraphicBufferConsumer::attachBuffer does not leak info in error case
-     */
-    public void test_attachBufferInfoLeak() throws Exception {
-        int slot = native_test_attachBufferInfoLeak();
-        assertTrue(String.format("Leaked slot 0x%08X", slot), slot == -1);
-    }
-
-    /**
-     * Check that IGraphicBufferProducer::queueBuffer does not leak info in error case
-     */
-    public void test_queueBufferInfoLeak() throws Exception {
-        int data = native_test_queueBufferInfoLeak();
-        assertTrue(String.format("Leaked buffer data 0x%08X", data), data == 0);
-    }
-
-    private static native int native_test_attachBufferInfoLeak();
-    private static native int native_test_queueBufferInfoLeak();
-}
diff --git a/tests/tests/security/src/android/security/cts/LoadEffectLibraryTest.java b/tests/tests/security/src/android/security/cts/LoadEffectLibraryTest.java
deleted file mode 100644
index 900ac7f..0000000
--- a/tests/tests/security/src/android/security/cts/LoadEffectLibraryTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.cts;
-
-import junit.framework.TestCase;
-
-public class LoadEffectLibraryTest extends TestCase {
-
-    static {
-        System.loadLibrary("ctssecurity_jni");
-    }
-
-    /**
-     * Checks that no binder calls to IAudioFlinger manages to load an effect library.
-     */
-    public void testLoadLibrary() throws Exception {
-        assertTrue(doLoadLibraryTest());
-    }
-
-    private static native boolean doLoadLibraryTest();
-
-}
diff --git a/tests/tests/security/src/android/security/cts/MediaPlayerInfoLeakTest.java b/tests/tests/security/src/android/security/cts/MediaPlayerInfoLeakTest.java
deleted file mode 100644
index e34fc05..0000000
--- a/tests/tests/security/src/android/security/cts/MediaPlayerInfoLeakTest.java
+++ /dev/null
@@ -1,46 +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.security.cts;
-
-import junit.framework.TestCase;
-
-public class MediaPlayerInfoLeakTest extends TestCase {
-
-    static {
-        System.loadLibrary("ctssecurity_jni");
-    }
-
-
-    /**
-     * Checks that IMediaPlayer::getCurrentPosition() does not leak info in error case
-     */
-    public void test_getCurrentPositionLeak() throws Exception {
-        int pos = native_test_getCurrentPositionLeak();
-        assertTrue(String.format("Leaked pos 0x%08X", pos), pos == 0);
-    }
-
-    /**
-     * Checks that IMediaPlayer::getDuration() does not leak info in error case
-     */
-    public void test_getDurationLeak() throws Exception {
-        int dur = native_test_getDurationLeak();
-        assertTrue(String.format("Leaked dur 0x%08X", dur), dur == 0);
-    }
-
-    private static native int native_test_getCurrentPositionLeak();
-    private static native int native_test_getDurationLeak();
-}
diff --git a/tests/tests/security/src/android/security/cts/SELinuxTest.java b/tests/tests/security/src/android/security/cts/SELinuxTest.java
index 736bdc9..24ad020 100644
--- a/tests/tests/security/src/android/security/cts/SELinuxTest.java
+++ b/tests/tests/security/src/android/security/cts/SELinuxTest.java
@@ -42,37 +42,6 @@
         System.loadLibrary("ctssecurity_jni");
     }
 
-    public void testMyJni() {
-        try {
-            checkSELinuxAccess(null, null, null, null, null);
-            fail("checkSELinuxAccess should have thrown");
-        } catch (NullPointerException e) {
-            // expected
-        }
-        try {
-            checkSELinuxContext(null);
-            fail("checkSELinuxContext should have thrown");
-        } catch (NullPointerException e) {
-            // expected
-        }
-    }
-
-    public void testCheckAccessSane() {
-        assertFalse(checkSELinuxAccess("a", "b", "c", "d", "e"));
-    }
-
-    public void testCheckContextSane() {
-        assertFalse(checkSELinuxContext("a"));
-    }
-
-    public void testZygoteContext() {
-        assertTrue(checkSELinuxContext("u:r:zygote:s0"));
-    }
-
-    public void testZygote() {
-        assertFalse(checkSELinuxAccess("u:r:zygote:s0", "u:object_r:runas_exec:s0", "file", "getattr", "/system/bin/run-as"));
-    }
-
     public void testCTSIsUntrustedApp() throws IOException {
         String found = KernelSettingsTest.getFile("/proc/self/attr/current");
         String expected = "u:r:untrusted_app:s0";
@@ -104,9 +73,5 @@
         assertEquals(getFileContext("/sys"), "u:object_r:sysfs:s0");
     }
 
-    private static native boolean checkSELinuxAccess(String scon, String tcon, String tclass, String perm, String extra);
-
-    private static native boolean checkSELinuxContext(String con);
-
     private static final native String getFileContext(String path);
 }
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 8073672..6f34498 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -242,10 +242,28 @@
 
         final MediaPlayerCrashListener mpcl = new MediaPlayerCrashListener();
 
-        Thread t = new Thread(new Runnable() {
+        class LooperThread extends Thread {
+            private Looper mLooper;
+
+            LooperThread(Runnable runner) {
+                super(runner);
+            }
+
             @Override
             public void run() {
                 Looper.prepare();
+                mLooper = Looper.myLooper();
+                super.run();
+            }
+
+            public void stopLooper() {
+                mLooper.quitSafely();
+            }
+        }
+
+        LooperThread t = new LooperThread(new Runnable() {
+            @Override
+            public void run() {
 
                 MediaPlayer mp = new MediaPlayer();
                 mp.setOnErrorListener(mpcl);
@@ -274,7 +292,7 @@
         String cve = name.replace("_", "-").toUpperCase();
         assertFalse("Device *IS* vulnerable to " + cve,
                     mpcl.waitForError() == MediaPlayer.MEDIA_ERROR_SERVER_DIED);
-        t.interrupt();
+        t.stopLooper();
     }
 
     private void doStagefrightTestMediaCodec(final int rid) throws Exception {
@@ -321,34 +339,46 @@
                 codec.configure(format, surface, null, 0);
                 codec.start();
                 MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
-                while (true) {
-                    int flags = ex.getSampleFlags();
-                    long time = ex.getSampleTime();
-                    int bufidx = codec.dequeueInputBuffer(5000);
-                    if (bufidx >= 0) {
-                        int n = ex.readSampleData(codec.getInputBuffer(bufidx), 0);
-                        if (n < 0) {
-                            flags = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
-                            time = 0;
-                            n = 0;
+                try {
+                    while (true) {
+                        int flags = ex.getSampleFlags();
+                        long time = ex.getSampleTime();
+                        int bufidx = codec.dequeueInputBuffer(5000);
+                        if (bufidx >= 0) {
+                            int n = ex.readSampleData(codec.getInputBuffer(bufidx), 0);
+                            if (n < 0) {
+                                flags = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+                                time = 0;
+                                n = 0;
+                            }
+                            codec.queueInputBuffer(bufidx, 0, n, time, flags);
+                            ex.advance();
                         }
-                        codec.queueInputBuffer(bufidx, 0, n, time, flags);
-                        ex.advance();
+                        int status = codec.dequeueOutputBuffer(info, 5000);
+                        if (status >= 0) {
+                            if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+                                break;
+                            }
+                            if (info.presentationTimeUs > TIMEOUT_NS / 1000) {
+                                Log.d(TAG, "stopping after 10 seconds worth of data");
+                                break;
+                            }
+                            codec.releaseOutputBuffer(status, true);
+                        }
                     }
-                    int status = codec.dequeueOutputBuffer(info, 5000);
-                    if (status >= 0) {
-                        if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
-                            break;
-                        }
-                        if (info.presentationTimeUs > TIMEOUT_NS / 1000) {
-                            Log.d(TAG, "stopping after 10 seconds worth of data");
-                            break;
-                        }
-                        codec.releaseOutputBuffer(status, true);
+                } catch (MediaCodec.CodecException ce) {
+                    if (ce.getErrorCode() == MediaCodec.CodecException.ERROR_RECLAIMED) {
+                        // This indicates that the remote service is dead, suggesting a crash.
+                        throw new RuntimeException(ce);
                     }
+                    // Other errors ignored.
+                } catch (IllegalStateException ise) {
+                    // Other errors ignored.
+                } finally {
+                    codec.release();
                 }
-                codec.release();
             }
         }
+        ex.release();
     }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
index 8cf20bd..074712e 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
@@ -45,6 +45,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -81,6 +82,11 @@
     InvokeCounter mOnCallAudioStateChangedCounter;
     InvokeCounter mOnPostDialWaitCounter;
     InvokeCounter mOnCannedTextResponsesLoadedCounter;
+    InvokeCounter mOnConnectionEventCounter;
+    InvokeCounter mOnExtrasChangedCounter;
+    InvokeCounter mOnPropertiesChangedCounter;
+    Bundle mPreviousExtras;
+    int mPreviousProperties = -1;
 
     InCallServiceCallbacks mInCallCallbacks;
     String mPreviousDefaultDialer = null;
@@ -192,6 +198,17 @@
             @Override
             public void onDetailsChanged(Call call, Call.Details details) {
                 Log.i(TAG, "onDetailsChanged, Call: " + call + ", Details: " + details);
+                if (!areBundlesEqual(mPreviousExtras, details.getExtras())) {
+                    mOnExtrasChangedCounter.invoke(call, details);
+                }
+                mPreviousExtras = details.getExtras();
+
+                if (mPreviousProperties != details.getCallProperties()) {
+                    mOnPropertiesChangedCounter.invoke(call, details);
+                    Log.i(TAG, "onDetailsChanged; properties changed from " + Call.Details.propertiesToString(mPreviousProperties) +
+                            " to " + Call.Details.propertiesToString(details.getCallProperties()));
+                }
+                mPreviousProperties = details.getCallProperties();
             }
             @Override
             public void onCallDestroyed(Call call) {
@@ -218,6 +235,10 @@
             public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {
                 mOnCannedTextResponsesLoadedCounter.invoke(call, cannedTextResponses);
             }
+            @Override
+            public void onConnectionEvent(Call call, String event, Bundle extras) {
+                mOnConnectionEventCounter.invoke(call, event, extras);
+            }
         };
 
         MockInCallService.setCallbacks(mInCallCallbacks);
@@ -228,6 +249,9 @@
         mOnCallAudioStateChangedCounter = new InvokeCounter("OnCallAudioStateChanged");
         mOnPostDialWaitCounter = new InvokeCounter("OnPostDialWait");
         mOnCannedTextResponsesLoadedCounter = new InvokeCounter("OnCannedTextResponsesLoaded");
+        mOnConnectionEventCounter = new InvokeCounter("OnConnectionEvent");
+        mOnExtrasChangedCounter = new InvokeCounter("OnDetailsChangedCounter");
+        mOnPropertiesChangedCounter = new InvokeCounter("OnPropertiesChangedCounter");
     }
 
     /**
@@ -297,6 +321,7 @@
         if (mInCallCallbacks.getService() != null) {
             currentCallCount = mInCallCallbacks.getService().getCallCount();
         }
+        int currentConnectionCount = getNumberOfConnections();
         placeNewCallWithPhoneAccount(extras, videoState);
 
         try {
@@ -311,6 +336,20 @@
         assertEquals("InCallService should contain 1 more call after adding a call.",
                 currentCallCount + 1,
                 mInCallCallbacks.getService().getCallCount());
+
+        // The connectionService.lock is released in
+        // MockConnectionService#onCreateOutgoingConnection, however the connection will not
+        // actually be added to the list of connections in the ConnectionService until shortly
+        // afterwards.  So there is still a potential for the lock to be released before it would
+        // be seen by calls to ConnectionService#getAllConnections().
+        // We will wait here until the list of connections includes one more connection to ensure
+        // that placing the call has fully completed.
+        final int expectedConnectionCount = currentConnectionCount + 1;
+        assertCSConnections(expectedConnectionCount);
+    }
+
+    int getNumberOfConnections() {
+        return CtsConnectionService.getAllConnectionsFromTelecom().size();
     }
 
     MockConnection verifyConnectionForOutgoingCall() {
@@ -520,6 +559,24 @@
     );
     }
 
+    void assertCSConnections(final int numConnections) {
+        waitUntilConditionIsTrueOrTimeout(new Condition() {
+                                              @Override
+                                              public Object expected() {
+                                                  return numConnections;
+                                              }
+
+                                              @Override
+                                              public Object actual() {
+                                                  return CtsConnectionService
+                                                          .getAllConnectionsFromTelecom()
+                                                          .size();
+                                              }
+                                          },
+                WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "ConnectionService should contain " + numConnections + " connections."
+        );
+    }
 
     void assertNumConnections(final MockConnectionService connService, final int numConnections) {
         waitUntilConditionIsTrueOrTimeout(new Condition() {
@@ -865,6 +922,30 @@
         );
     }
 
+    /**
+     * Asserts that a call's properties are as expected.
+     *
+     * @param call The call.
+     * @param properties The expected properties.
+     */
+    public void assertCallProperties(final Call call, final int properties) {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return true;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        return call.getDetails().hasProperty(properties);
+                    }
+                },
+                TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Call should have properties " + properties
+        );
+    }
+
     void waitUntilConditionIsTrueOrTimeout(Condition condition, long timeout,
             String description) {
         final long start = System.currentTimeMillis();
@@ -982,4 +1063,25 @@
             }
         }
     }
+
+    public static boolean areBundlesEqual(Bundle extras, Bundle newExtras) {
+        if (extras == null || newExtras == null) {
+            return extras == newExtras;
+        }
+
+        if (extras.size() != newExtras.size()) {
+            return false;
+        }
+
+        for (String key : extras.keySet()) {
+            if (key != null) {
+                final Object value = extras.get(key);
+                final Object newValue = newExtras.get(key);
+                if (!Objects.equals(value, newValue)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java b/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
index 0be05d66..c8e927f 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
@@ -29,24 +29,32 @@
 import android.telecom.ConnectionRequest;
 import android.telecom.DisconnectCause;
 import android.telecom.GatewayInfo;
-import android.telecom.InCallService;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.StatusHints;
 import android.telecom.TelecomManager;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.List;
 
 /**
  * Suites of tests that verifies the various Call details.
  */
 public class CallDetailsTest extends BaseTelecomTestWithMockServices {
 
+    /**
+     * {@link Connection#PROPERTY_HIGH_DEF_AUDIO} is @hide, so define it here for now.
+     */
+    public static final int PROPERTY_HIGH_DEF_AUDIO = 1<<2;
+
+    /**
+     * {@link Connection#PROPERTY_WIFI} is @hide, so define it here for now.
+     */
+    public static final int PROPERTY_WIFI = 1<<3;
+    public static final int CONNECTION_PROPERTIES =  PROPERTY_HIGH_DEF_AUDIO | PROPERTY_WIFI;
     public static final int CONNECTION_CAPABILITIES =
-            Connection.CAPABILITY_HOLD | Connection.CAPABILITY_MUTE |
-            /**
-             * CAPABILITY_HIGH_DEF_AUDIO & CAPABILITY_WIFI are hidden, so
-             * hardcoding the values for now.
-             */
-            0x00008000 | 0x00010000;
+            Connection.CAPABILITY_HOLD | Connection.CAPABILITY_MUTE;
     public static final int CALL_CAPABILITIES =
             Call.Details.CAPABILITY_HOLD | Call.Details.CAPABILITY_MUTE;
     public static final int CALL_PROPERTIES =
@@ -57,14 +65,17 @@
     public static final String TEST_CHILD_NUMBER = "650-555-1212";
     public static final String TEST_FORWARDED_NUMBER = "650-555-1212";
     public static final String TEST_EXTRA_KEY = "com.test.extra.TEST";
+    public static final String TEST_EXTRA_KEY2 = "com.test.extra.TEST2";
+    public static final String TEST_EXTRA_KEY3 = "com.test.extra.TEST3";
     public static final int TEST_EXTRA_VALUE = 10;
+    public static final String TEST_EVENT = "com.test.event.TEST";
 
     private StatusHints mStatusHints;
     private Bundle mExtras = new Bundle();
 
     private MockInCallService mInCallService;
     private Call mCall;
-    private Connection mConnection;
+    private MockConnection mConnection;
 
     @Override
     protected void setUp() throws Exception {
@@ -79,9 +90,10 @@
                             Connection connection = super.onCreateOutgoingConnection(
                                     connectionManagerPhoneAccount,
                                     request);
-                            mConnection = connection;
+                            mConnection = (MockConnection) connection;
                             // Modify the connection object created with local values.
                             connection.setConnectionCapabilities(CONNECTION_CAPABILITIES);
+                            connection.setConnectionProperties(CONNECTION_PROPERTIES);
                             connection.setCallerDisplayName(
                                     CALLER_DISPLAY_NAME,
                                     CALLER_DISPLAY_NAME_PRESENTATION);
@@ -402,6 +414,189 @@
     }
 
     /**
+     * Tests that {@link Connection} extras changes made via {@link Connection#putExtras(Bundle)}
+     * are propagated to the {@link Call} via
+     * {@link android.telecom.Call.Callback#onDetailsChanged(Call, Call.Details)}.
+     */
+    public void testConnectionPutExtras() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        Bundle testBundle = new Bundle();
+        testBundle.putString(TEST_EXTRA_KEY, TEST_SUBJECT);
+        testBundle.putInt(TEST_EXTRA_KEY2, TEST_EXTRA_VALUE);
+        mConnection.putExtras(testBundle);
+        // Wait for the 2nd invocation; setExtras is called in the setup method.
+        mOnExtrasChangedCounter.waitForCount(2, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+
+        Bundle extras = mCall.getDetails().getExtras();
+        assertEquals(2, extras.size());
+        assertTrue(extras.containsKey(TEST_EXTRA_KEY));
+        assertEquals(TEST_SUBJECT, extras.getString(TEST_EXTRA_KEY));
+        assertTrue(extras.containsKey(TEST_EXTRA_KEY2));
+        assertEquals(TEST_EXTRA_VALUE, extras.getInt(TEST_EXTRA_KEY2));
+    }
+
+    /**
+     * Tests that {@link Connection} extras changes made via {@link Connection#removeExtras(List)}
+     * are propagated to the {@link Call} via
+     * {@link android.telecom.Call.Callback#onDetailsChanged(Call, Call.Details)}.
+     */
+    public void testConnectionRemoveExtras() {
+        testConnectionPutExtras();
+
+        mConnection.removeExtras(Arrays.asList(TEST_EXTRA_KEY));
+        // testConnectionPutExtra will have waited for the 2nd invocation, so wait for the 3rd here.
+        mOnExtrasChangedCounter.waitForCount(3, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+
+        Bundle extras = mCall.getDetails().getExtras();
+        assertEquals(1, extras.size());
+        assertFalse(extras.containsKey(TEST_EXTRA_KEY));
+        assertTrue(extras.containsKey(TEST_EXTRA_KEY2));
+        assertEquals(TEST_EXTRA_VALUE, extras.getInt(TEST_EXTRA_KEY2));
+    }
+
+    /**
+     * Tests that {@link Call} extras changes made via {@link Call#putExtras(Bundle)} are propagated
+     * to {@link Connection#onExtrasChanged(Bundle)}.
+     */
+    public void testCallPutExtras() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        Bundle testBundle = new Bundle();
+        testBundle.putString(TEST_EXTRA_KEY, TEST_SUBJECT);
+        final InvokeCounter counter = mConnection.getInvokeCounter(
+                MockConnection.ON_EXTRAS_CHANGED);
+        mCall.putExtras(testBundle);
+        counter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+        Bundle extras = mConnection.getExtras();
+
+        assertNotNull(extras);
+        assertTrue(extras.containsKey(TEST_EXTRA_KEY));
+        assertEquals(TEST_SUBJECT, extras.getString(TEST_EXTRA_KEY));
+    }
+
+    /**
+     * Tests that {@link Call} extra operations using {@link Call#removeExtras(List)} are propagated
+     * to the {@link Connection} via {@link Connection#onExtrasChanged(Bundle)}.
+     *
+     * This test specifically tests addition and removal of extras values.
+     */
+    public void testCallRemoveExtras() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        Bundle testBundle = new Bundle();
+        testBundle.putString(TEST_EXTRA_KEY, TEST_SUBJECT);
+        testBundle.putInt(TEST_EXTRA_KEY2, TEST_EXTRA_VALUE);
+        testBundle.putString(TEST_EXTRA_KEY3, TEST_SUBJECT);
+        final InvokeCounter counter = mConnection.getInvokeCounter(
+                MockConnection.ON_EXTRAS_CHANGED);
+        mCall.putExtras(testBundle);
+        counter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+        Bundle extras = mConnection.getExtras();
+
+        assertNotNull(extras);
+        assertTrue(extras.containsKey(TEST_EXTRA_KEY));
+        assertEquals(TEST_SUBJECT, extras.getString(TEST_EXTRA_KEY));
+        assertTrue(extras.containsKey(TEST_EXTRA_KEY2));
+        assertEquals(TEST_EXTRA_VALUE, extras.getInt(TEST_EXTRA_KEY2));
+        assertTrue(extras.containsKey(TEST_EXTRA_KEY3));
+        assertEquals(TEST_SUBJECT, extras.getString(TEST_EXTRA_KEY3));
+
+        mCall.removeExtras(Arrays.asList(TEST_EXTRA_KEY));
+        counter.waitForCount(2, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+        extras = mConnection.getExtras();
+        assertNotNull(extras);
+        assertFalse(extras.containsKey(TEST_EXTRA_KEY));
+        assertTrue(extras.containsKey(TEST_EXTRA_KEY2));
+        assertEquals(TEST_EXTRA_VALUE, extras.getInt(TEST_EXTRA_KEY2));
+        assertTrue(extras.containsKey(TEST_EXTRA_KEY3));
+        assertEquals(TEST_SUBJECT, extras.getString(TEST_EXTRA_KEY3));
+
+        mCall.removeExtras(Arrays.asList(TEST_EXTRA_KEY2, TEST_EXTRA_KEY3));
+        counter.waitForCount(3, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+        extras = mConnection.getExtras();
+        assertTrue(extras.isEmpty());
+    }
+
+    /**
+     * Tests that {@link Connection} events are propagated from
+     * {@link Connection#sendConnectionEvent(String, Bundle)} to
+     * {@link android.telecom.Call.Callback#onConnectionEvent(Call, String, Bundle)}.
+     */
+    public void testConnectionEvent() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        Bundle testBundle = new Bundle();
+        testBundle.putString(TEST_EXTRA_KEY, TEST_SUBJECT);
+
+        mConnection.sendConnectionEvent(Connection.EVENT_CALL_PULL_FAILED, testBundle);
+        mOnConnectionEventCounter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+        String event = (String) (mOnConnectionEventCounter.getArgs(0)[1]);
+        Bundle extras = (Bundle) (mOnConnectionEventCounter.getArgs(0)[2]);
+
+        assertEquals(Connection.EVENT_CALL_PULL_FAILED, event);
+        assertNotNull(extras);
+        assertTrue(extras.containsKey(TEST_EXTRA_KEY));
+        assertEquals(TEST_SUBJECT, extras.getString(TEST_EXTRA_KEY));
+    }
+
+    /**
+     * Tests that {@link Call} events are propagated from {@link Call#sendCallEvent(String, Bundle)}
+     * to {@link Connection#onCallEvent(String, Bundle)}.
+     */
+    public void testCallEvent() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        Bundle testBundle = new Bundle();
+        testBundle.putString(TEST_EXTRA_KEY, TEST_SUBJECT);
+        final InvokeCounter counter = mConnection.getInvokeCounter(MockConnection.ON_CALL_EVENT);
+        mCall.sendCallEvent(TEST_EVENT, testBundle);
+        counter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+
+        String event = (String) (counter.getArgs(0)[0]);
+        Bundle extras = (Bundle) (counter.getArgs(0)[1]);
+
+        assertEquals(TEST_EVENT, event);
+        assertNotNull(extras);
+        assertTrue(extras.containsKey(TEST_EXTRA_KEY));
+        assertEquals(TEST_SUBJECT, extras.getString(TEST_EXTRA_KEY));
+    }
+
+    /**
+     * Tests that a request to pull an external call via {@link Call#pullExternalCall()} is
+     * communicated to the {@link Connection} via {@link Connection#onPullExternalCall()}.
+     */
+    public void testPullExternalCall() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        // First, configure the connection as an external call which is pullable.
+        int properties = mConnection.getConnectionProperties();
+        int capabilities = mConnection.getConnectionCapabilities();
+        properties |= Connection.PROPERTY_IS_EXTERNAL_CALL;
+        capabilities |= Connection.CAPABILITY_CAN_PULL_CALL;
+        mConnection.setConnectionCapabilities(capabilities);
+        mConnection.setConnectionProperties(properties);
+        assertCallProperties(mCall, Call.Details.PROPERTY_IS_EXTERNAL_CALL);
+
+        final InvokeCounter counter = mConnection.getInvokeCounter(
+                MockConnection.ON_PULL_EXTERNAL_CALL);
+        mCall.pullExternalCall();
+        counter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+    }
+
+    /**
      * Asserts that a call's capabilities are as expected.
      *
      * @param call The call.
diff --git a/tests/tests/telecom/src/android/telecom/cts/CallTest.java b/tests/tests/telecom/src/android/telecom/cts/CallTest.java
index efbb69f..b892ede 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CallTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CallTest.java
@@ -31,6 +31,8 @@
         assertTrue(Call.Details.can(CAPABILITY_MERGE_CONFERENCE
                 | CAPABILITY_DISCONNECT_FROM_CONFERENCE | CAPABILITY_MUTE,
                 CAPABILITY_MUTE));
+        assertTrue(Call.Details.can(CAPABILITY_CAN_PAUSE_VIDEO, CAPABILITY_CAN_PAUSE_VIDEO));
+        assertTrue(Call.Details.can(CAPABILITY_CAN_PULL_CALL, CAPABILITY_CAN_PULL_CALL));
 
         assertFalse(Call.Details.can(CAPABILITY_MUTE, CAPABILITY_HOLD));
         assertFalse(Call.Details.can(CAPABILITY_MERGE_CONFERENCE
@@ -78,6 +80,7 @@
         assertTrue(Call.Details.hasProperty(PROPERTY_HIGH_DEF_AUDIO, PROPERTY_HIGH_DEF_AUDIO));
         assertTrue(Call.Details.hasProperty(PROPERTY_HIGH_DEF_AUDIO | PROPERTY_CONFERENCE
                 | PROPERTY_WIFI, PROPERTY_CONFERENCE));
+        assertTrue(Call.Details.hasProperty(PROPERTY_IS_EXTERNAL_CALL, PROPERTY_IS_EXTERNAL_CALL));
 
         assertFalse(Call.Details.hasProperty(PROPERTY_WIFI, PROPERTY_CONFERENCE));
         assertFalse(Call.Details.hasProperty(PROPERTY_HIGH_DEF_AUDIO | PROPERTY_CONFERENCE
diff --git a/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java b/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
index 508870c..c3168f6 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
@@ -29,8 +29,11 @@
 import android.telecom.StatusHints;
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
+import android.util.Log;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
 /**
  * Extended suite of tests that use {@link CtsConnectionService} and {@link MockInCallService} to
@@ -38,6 +41,11 @@
  */
 public class ConferenceTest extends BaseTelecomTestWithMockServices {
 
+    private static final String TEST_EXTRA_KEY_1 = "android.telecom.test.KEY1";
+    private static final String TEST_EXTRA_KEY_2 = "android.telecom.test.KEY2";
+    private static final String TEST_EXTRA_VALUE_1 = "test";
+    private static final int TEST_EXTRA_VALUE_2 = 42;
+
     public static final int CONF_CAPABILITIES = Connection.CAPABILITY_SEPARATE_FROM_CONFERENCE |
             Connection.CAPABILITY_DISCONNECT_FROM_CONFERENCE | Connection.CAPABILITY_HOLD |
             Connection.CAPABILITY_MERGE_CONFERENCE | Connection.CAPABILITY_SWAP_CONFERENCE;
@@ -45,7 +53,7 @@
     private Call mCall1, mCall2;
     private MockConnection mConnection1, mConnection2;
     MockInCallService mInCallService;
-    Conference mConferenceObject;
+    MockConference mConferenceObject;
 
     @Override
     protected void setUp() throws Exception {
@@ -213,6 +221,94 @@
         assertCallState(conf, Call.STATE_DISCONNECTED);
     }
 
+    /**
+     * Tests end to end propagation of the {@link Conference} properties to the associated
+     * {@link Call}.
+     */
+    public void testConferenceProperties() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+        final Call conf = mInCallService.getLastConferenceCall();
+        assertCallState(conf, Call.STATE_ACTIVE);
+
+        int properties  = mConferenceObject.getConnectionProperties();
+        properties |= Connection.PROPERTY_IS_EXTERNAL_CALL;
+
+        mConferenceObject.setConnectionProperties(properties);
+
+        // Wait for 2nd properties change; the first will be when the conference is marked with
+        // Call.Details.PROPERTY_CONFERENCE.
+        assertCallProperties(conf, Call.Details.PROPERTY_IS_EXTERNAL_CALL);
+        assertTrue(conf.getDetails().hasProperty(Call.Details.PROPERTY_IS_EXTERNAL_CALL));
+    }
+
+    /**
+     * Verifies {@link Conference#putExtras(Bundle)} calls are propagated to
+     * {@link android.telecom.Call.Callback#onDetailsChanged(Call, Call.Details)}.
+     */
+    public void testConferencePutExtras() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+        final Call conf = mInCallService.getLastConferenceCall();
+        assertCallState(conf, Call.STATE_ACTIVE);
+
+        Bundle extras = new Bundle();
+        extras.putString(TEST_EXTRA_KEY_1, TEST_EXTRA_VALUE_1);
+        extras.putInt(TEST_EXTRA_KEY_2, TEST_EXTRA_VALUE_2);
+        mConferenceObject.putExtras(extras);
+
+        mOnExtrasChangedCounter.waitForCount(1);
+
+        assertTrue(areBundlesEqual(extras, conf.getDetails().getExtras()));
+    }
+
+    /**
+     * Verifies {@link Conference#removeExtras(List)} calls are propagated to
+     * {@link android.telecom.Call.Callback#onDetailsChanged(Call, Call.Details)}.
+     */
+    public void testConferenceRemoveExtras() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+        final Call conf = mInCallService.getLastConferenceCall();
+        assertCallState(conf, Call.STATE_ACTIVE);
+
+        Bundle extras = new Bundle();
+        extras.putString(TEST_EXTRA_KEY_1, TEST_EXTRA_VALUE_1);
+        extras.putInt(TEST_EXTRA_KEY_2, TEST_EXTRA_VALUE_2);
+        mConferenceObject.putExtras(extras);
+        mOnExtrasChangedCounter.waitForCount(1);
+
+        mConferenceObject.removeExtras(Arrays.asList(TEST_EXTRA_KEY_1));
+        mOnExtrasChangedCounter.waitForCount(2);
+        extras = mConferenceObject.getExtras();
+
+        assertFalse(extras.containsKey(TEST_EXTRA_KEY_1));
+        assertTrue(extras.containsKey(TEST_EXTRA_KEY_2));
+    }
+
+    /**
+     * Verifies {@link android.telecom.Call#putExtras(Bundle)} changes are propagated to
+     * {@link Conference#onExtrasChanged(Bundle)}.
+     */
+    public void testConferenceOnExtraschanged() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+        final Call conf = mInCallService.getLastConferenceCall();
+        assertCallState(conf, Call.STATE_ACTIVE);
+
+        Bundle extras = new Bundle();
+        extras.putString(TEST_EXTRA_KEY_1, TEST_EXTRA_VALUE_1);
+        extras.putInt(TEST_EXTRA_KEY_2, TEST_EXTRA_VALUE_2);
+        conf.putExtras(extras);
+        mConferenceObject.mOnExtrasChanged.waitForCount(1);
+
+        assertTrue(areBundlesEqual(extras, mConferenceObject.getExtras()));
+    }
+
     public void testConferenceAddAndRemoveConnection() {
         if (!mShouldTestTelecom) {
             return;
diff --git a/tests/tests/telecom/src/android/telecom/cts/ConnectionTest.java b/tests/tests/telecom/src/android/telecom/cts/ConnectionTest.java
index b6818c8..874f116 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ConnectionTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ConnectionTest.java
@@ -27,6 +27,8 @@
 import android.telecom.TelecomManager;
 import android.test.AndroidTestCase;
 
+import java.util.Arrays;
+import java.util.List;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
@@ -162,6 +164,22 @@
         assertEquals(capabilities, connection.getConnectionCapabilities());
     }
 
+    public void testSetAndGetConnectionProperties() {
+        if (!shouldTestTelecom(getContext())) {
+            return;
+        }
+
+        final Semaphore lock = new Semaphore(0);
+        Connection connection = createConnection(lock);
+        waitForStateChange(lock);
+
+        final int properties = Connection.PROPERTY_IS_EXTERNAL_CALL;
+
+        connection.setConnectionProperties(properties);
+
+        assertEquals(properties, connection.getConnectionProperties());
+    }
+
     public void testSetAndGetDisconnectCause() {
         if (!shouldTestTelecom(getContext())) {
             return;
@@ -215,6 +233,79 @@
         assertTrue(extras.getBoolean("test-extra-key"));
     }
 
+    /**
+     * Basic local test of adding extra keys via {@link Connection#removeExtras(List)}.
+     *
+     * Extended end-to-end passing of extras is verified in
+     * {@link CallDetailsTest#testConnectionPutExtras()} and
+     * @link CallDetailsTest#testConnectionRemoveExtras()}.
+     */
+    public void testPutExtras() {
+        if (!shouldTestTelecom(getContext())) {
+            return;
+        }
+
+        final Semaphore lock = new Semaphore(0);
+        Connection connection = createConnection(lock);
+        waitForStateChange(lock);
+
+        assertEquals(null, connection.getExtras());
+
+        final Bundle extras = new Bundle();
+        extras.putBoolean("test-extra-key", true);
+        connection.putExtras(extras);
+
+        final Bundle retrieved = connection.getExtras();
+        assertNotNull(retrieved);
+        assertTrue(extras.getBoolean("test-extra-key"));
+    }
+
+    /**
+     * Basic local test of removing extra keys via {@link Connection#removeExtras(List)}.
+     *
+     * Extended end-to-end passing of extras is verified in
+     * {@link CallDetailsTest#testConnectionPutExtras()} and
+     * @link CallDetailsTest#testConnectionRemoveExtras()}.
+     */
+    public void testRemoveExtras() {
+        if (!shouldTestTelecom(getContext())) {
+            return;
+        }
+
+        final Semaphore lock = new Semaphore(0);
+        Connection connection = createConnection(lock);
+        waitForStateChange(lock);
+
+        assertEquals(null, connection.getExtras());
+
+        final Bundle extras = new Bundle();
+        extras.putBoolean("test-extra-key", true);
+        connection.putExtras(extras);
+        connection.removeExtras(Arrays.asList("test-extra-key"));
+
+        final Bundle retrieved = connection.getExtras();
+        assertNotNull(retrieved);
+        assertFalse(extras.containsKey("test-extra-key"));
+    }
+
+    /**
+     * Tests that the {@link Connection#sendConnectionEvent(String, Bundle)} method exists and can
+     * be called.
+     *
+     * Actual end-to-end tests can be found in {@link CallDetailsTest#testConnectionEvent()}.
+     */
+    public void testSendConnectionEvent() {
+        if (!shouldTestTelecom(getContext())) {
+            return;
+        }
+
+        final Semaphore lock = new Semaphore(0);
+        Connection connection = createConnection(lock);
+        waitForStateChange(lock);
+
+        connection.sendConnectionEvent("test", null);
+    }
+
     public void testSetAndGetStatusHints() {
         if (!shouldTestTelecom(getContext())) {
             return;
@@ -293,6 +384,18 @@
                         | Connection.CAPABILITY_MANAGE_CONFERENCE));
     }
 
+    /**
+     * Tests the {@link Connection#propertiesToString(int)} method.
+     */
+    public void testPropertiesToString() {
+        if (!shouldTestTelecom(getContext())) {
+            return;
+        }
+
+        assertEquals("[Properties: PROPERTY_IS_EXTERNAL_CALL]",
+                Connection.propertiesToString(Connection.PROPERTY_IS_EXTERNAL_CALL));
+    }
+
     private static Connection createConnection(final Semaphore lock) {
         BasicConnection connection = new BasicConnection();
         connection.setLock(lock);
diff --git a/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
index 2364986..e820e10 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
@@ -29,6 +29,7 @@
 import android.util.Log;
 
 import java.util.Collection;
+import java.util.Collections;
 
 /**
  * This is the official ConnectionService for Telecom's CTS App. Since telecom requires that a
@@ -154,6 +155,9 @@
 
     public static Collection<Connection> getAllConnectionsFromTelecom() {
         synchronized(sLock) {
+            if (sTelecomConnectionService == null) {
+                return Collections.EMPTY_LIST;
+            }
             return sTelecomConnectionService.getAllConnections();
         }
     }
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockConference.java b/tests/tests/telecom/src/android/telecom/cts/MockConference.java
index 647d039..d84610d 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockConference.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockConference.java
@@ -16,6 +16,7 @@
 
 package android.telecom.cts;
 
+import android.os.Bundle;
 import android.telecom.Conference;
 import android.telecom.Connection;
 import android.telecom.DisconnectCause;
@@ -31,6 +32,8 @@
 
     private RemoteConference mRemoteConference = null;
     private String mDtmfString = "";
+    public BaseTelecomTestWithMockServices.InvokeCounter mOnExtrasChanged =
+            new BaseTelecomTestWithMockServices.InvokeCounter("onExtrasChanged");
 
     public MockConference(PhoneAccountHandle phoneAccount) {
         super(phoneAccount);
@@ -149,4 +152,9 @@
     public String getDtmfString() {
         return mDtmfString;
     }
+
+    @Override
+    public void onExtrasChanged(Bundle extras) {
+        mOnExtrasChanged.invoke(extras);
+    }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockConnection.java b/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
index fe33a8d..4436219 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
@@ -17,6 +17,8 @@
 package android.telecom.cts;
 
 import static android.telecom.CallAudioState.*;
+
+import android.os.Bundle;
 import android.telecom.CallAudioState;
 import android.telecom.Connection;
 import android.telecom.DisconnectCause;
@@ -32,6 +34,9 @@
  */
 public class MockConnection extends Connection {
     public static final int ON_POST_DIAL_WAIT = 1;
+    public static final int ON_CALL_EVENT = 2;
+    public static final int ON_PULL_EXTERNAL_CALL = 3;
+    public static final int ON_EXTRAS_CHANGED = 4;
 
     private CallAudioState mCallAudioState =
             new CallAudioState(false, CallAudioState.ROUTE_EARPIECE, ROUTE_EARPIECE | ROUTE_SPEAKER);
@@ -158,6 +163,30 @@
         }
     }
 
+    @Override
+    public void onCallEvent(String event, Bundle extras) {
+        super.onCallEvent(event, extras);
+        if (mInvokeCounterMap.get(ON_CALL_EVENT) != null) {
+            mInvokeCounterMap.get(ON_CALL_EVENT).invoke(event, extras);
+        }
+    }
+
+    @Override
+    public void onPullExternalCall() {
+        super.onPullExternalCall();
+        if (mInvokeCounterMap.get(ON_PULL_EXTERNAL_CALL) != null) {
+            mInvokeCounterMap.get(ON_PULL_EXTERNAL_CALL).invoke();
+        }
+    }
+
+    @Override
+    public void onExtrasChanged(Bundle extras) {
+        super.onExtrasChanged(extras);
+        if (mInvokeCounterMap.get(ON_EXTRAS_CHANGED) != null) {
+            mInvokeCounterMap.get(ON_EXTRAS_CHANGED).invoke(extras);
+        }
+    }
+
     public int getCurrentState()  {
         return mState;
     }
@@ -239,6 +268,12 @@
         switch (counterIndex) {
             case ON_POST_DIAL_WAIT:
                 return "onPostDialWait";
+            case ON_CALL_EVENT:
+                return "onCallEvent";
+            case ON_PULL_EXTERNAL_CALL:
+                return "onPullExternalCall";
+            case ON_EXTRAS_CHANGED:
+                return "onExtrasChanged";
             default:
                 return "Callback";
         }
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java b/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java
index c371ed1..9776c64 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertTrue;
 
 import android.content.Intent;
+import android.os.Bundle;
 import android.telecom.Call;
 import android.telecom.CallAudioState;
 import android.telecom.InCallService;
@@ -58,6 +59,7 @@
         public void onCallAudioStateChanged(CallAudioState audioState) {}
         public void onPostDialWait(Call call, String remainingPostDialSequence) {}
         public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {}
+        public void onConnectionEvent(Call call, String event, Bundle extras) {}
 
         final public MockInCallService getService() {
             return mService;
@@ -142,6 +144,14 @@
                 getCallbacks().onCannedTextResponsesLoaded(call, cannedTextResponses);
             }
         }
+
+        @Override
+        public void onConnectionEvent(Call call, String event, Bundle extras) {
+            super.onConnectionEvent(call, event, extras);
+            if (getCallbacks() != null) {
+                getCallbacks().onConnectionEvent(call, event, extras);
+            }
+        }
     };
 
     private void saveVideoCall(Call call, VideoCall videoCall) {
diff --git a/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java b/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
index cc03288..4374516 100644
--- a/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.graphics.Color;
 import android.net.Uri;
+import android.os.Bundle;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
@@ -38,6 +39,16 @@
 public class PhoneAccountOperationsTest extends InstrumentationTestCase {
     public static final PhoneAccountHandle TEST_PHONE_ACCOUNT_HANDLE =
             new PhoneAccountHandle(new ComponentName(PACKAGE, COMPONENT), ACCOUNT_ID);
+    public static final Bundle TEST_BUNDLE = createTestBundle();
+    public static final int TEST_LENGTH = 10;
+    public static final String TEST_ENCODING = "enUS";
+
+    private static Bundle createTestBundle() {
+        Bundle testBundle = new Bundle();
+        testBundle.putInt(PhoneAccount.EXTRA_CALL_SUBJECT_MAX_LENGTH, TEST_LENGTH);
+        testBundle.putString(PhoneAccount.EXTRA_CALL_SUBJECT_CHARACTER_ENCODING, TEST_ENCODING);
+        return testBundle;
+    }
 
     public static final PhoneAccount TEST_SIM_PHONE_ACCOUNT = PhoneAccount.builder(
             TEST_PHONE_ACCOUNT_HANDLE, ACCOUNT_LABEL)
@@ -59,6 +70,7 @@
             .setShortDescription(ACCOUNT_LABEL)
             .setSupportedUriSchemes(Arrays.asList(
                     PhoneAccount.SCHEME_TEL, PhoneAccount.SCHEME_VOICEMAIL))
+            .setExtras(TEST_BUNDLE)
             .build();
 
     public static final PhoneAccount TEST_CALL_MANAGER_PHONE_ACCOUNT = PhoneAccount.builder(
@@ -185,6 +197,22 @@
                         PhoneAccount.CAPABILITY_VIDEO_CALLING));
     }
 
+    public void testRegisterPhoneAccount_CheckExtras() throws Exception {
+        if (!shouldTestTelecom(mContext)) {
+            return;
+        }
+        mTelecomManager.registerPhoneAccount(TEST_NO_SIM_PHONE_ACCOUNT);
+        PhoneAccount retrievedPhoneAccount = mTelecomManager.getPhoneAccount(
+                TEST_PHONE_ACCOUNT_HANDLE);
+        Bundle extras = retrievedPhoneAccount.getExtras();
+        assertTrue(extras.containsKey(PhoneAccount.EXTRA_CALL_SUBJECT_CHARACTER_ENCODING));
+        assertEquals(TEST_ENCODING,
+                extras.getString(PhoneAccount.EXTRA_CALL_SUBJECT_CHARACTER_ENCODING));
+        assertTrue(extras.containsKey(PhoneAccount.EXTRA_CALL_SUBJECT_MAX_LENGTH));
+        assertEquals(TEST_LENGTH,
+                extras.getInt(PhoneAccount.EXTRA_CALL_SUBJECT_MAX_LENGTH));
+    }
+
     public void testRegisterPhoneAccount_CheckURISchemeSupported() throws Exception {
         if (!shouldTestTelecom(mContext)) {
             return;
diff --git a/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java b/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java
index 787966a..eeb2ad7 100644
--- a/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java
@@ -343,6 +343,35 @@
         mRemoteConferenceObject.unregisterCallback(callback);
     }
 
+    public void testRemoteConferenceCallbacks_ConnectionProperties() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+        Handler handler = setupRemoteConferenceCallbacksTest();
+
+        final InvokeCounter callbackInvoker =
+                new InvokeCounter("testRemoteConferenceCallbacks_ConnectionProperties");
+        RemoteConference.Callback callback;
+
+        callback = new RemoteConference.Callback() {
+            @Override
+            public void onConnectionPropertiesChanged(
+                    RemoteConference conference,
+                    int connectionProperties) {
+                super.onConnectionPropertiesChanged(conference, connectionProperties);
+                callbackInvoker.invoke(conference, connectionProperties);
+            }
+        };
+        mRemoteConferenceObject.registerCallback(callback, handler);
+        int properties = mRemoteConference.getConnectionCapabilities()
+                | Connection.PROPERTY_IS_EXTERNAL_CALL;
+        mRemoteConference.setConnectionProperties(properties);
+        callbackInvoker.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+        assertEquals(mRemoteConferenceObject, callbackInvoker.getArgs(0)[0]);
+        assertEquals(properties, callbackInvoker.getArgs(0)[1]);
+        mRemoteConferenceObject.unregisterCallback(callback);
+    }
+
     public void testRemoteConferenceCallbacks_ConferenceableConnections() {
         if (!mShouldTestTelecom) {
             return;
@@ -402,6 +431,7 @@
         mRemoteConferenceObject.unregisterCallback(callback);
     }
 
+
     public void testRemoteConferenceCallbacks_Extras() {
         if (!mShouldTestTelecom) {
             return;
@@ -425,7 +455,7 @@
         mRemoteConference.setExtras(extras);
         callbackInvoker.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
         assertEquals(mRemoteConferenceObject, callbackInvoker.getArgs(0)[0]);
-        assertEquals(extras, callbackInvoker.getArgs(0)[1]);
+        assertTrue(areBundlesEqual(extras, (Bundle) callbackInvoker.getArgs(0)[1]));
         mRemoteConferenceObject.unregisterCallback(callback);
     }
 
diff --git a/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java b/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java
index 7d095db..81080b0 100644
--- a/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java
@@ -238,7 +238,36 @@
         assertEquals(mRemoteConnectionObject, callbackInvoker.getArgs(0)[0]);
         assertEquals(capabilities, callbackInvoker.getArgs(0)[1]);
         mRemoteConnectionObject.unregisterCallback(callback);
+    }
 
+    public void testRemoteConnectionCallbacks_ConnectionProperties() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        Handler handler = setupRemoteConnectionCallbacksTest();
+
+        final InvokeCounter callbackInvoker =
+                new InvokeCounter("testRemoteConnectionCallbacks_ConnectionCapabilities");
+        RemoteConnection.Callback callback;
+
+        callback = new RemoteConnection.Callback() {
+            @Override
+            public void onConnectionPropertiesChanged(
+                    RemoteConnection connection,
+                    int connectionProperties) {
+                super.onConnectionPropertiesChanged(connection, connectionProperties);
+                callbackInvoker.invoke(connection, connectionProperties);
+            }
+        };
+        mRemoteConnectionObject.registerCallback(callback, handler);
+        int properties = mRemoteConnection.getConnectionCapabilities()
+                | Connection.PROPERTY_IS_EXTERNAL_CALL;
+        mRemoteConnection.setConnectionProperties(properties);
+        callbackInvoker.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+        assertEquals(mRemoteConnectionObject, callbackInvoker.getArgs(0)[0]);
+        assertEquals(properties, callbackInvoker.getArgs(0)[1]);
+        mRemoteConnectionObject.unregisterCallback(callback);
     }
 
     public void testRemoteConnectionCallbacks_PostDialWait() {
@@ -525,9 +554,42 @@
         mRemoteConnection.setExtras(extras);
         callbackInvoker.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
         assertEquals(mRemoteConnectionObject, callbackInvoker.getArgs(0)[0]);
-        assertEquals(extras, callbackInvoker.getArgs(0)[1]);
+        assertTrue(areBundlesEqual(extras, (Bundle) callbackInvoker.getArgs(0)[1]));
         mRemoteConnectionObject.unregisterCallback(callback);
+    }
 
+    /**
+     * Verifies that a {@link RemoteConnection} receives a
+     * {@link Connection#sendConnectionEvent(String, Bundle)} notification.
+     */
+    public void testRemoteConnectionCallbacks_ConnectionEvent() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        Handler handler = setupRemoteConnectionCallbacksTest();
+
+        final InvokeCounter callbackInvoker =
+                new InvokeCounter("testRemoteConnectionCallbacks_Extras");
+        RemoteConnection.Callback callback;
+
+        callback = new RemoteConnection.Callback() {
+            @Override
+            public void onConnectionEvent(RemoteConnection connection, String event,
+                    Bundle extras) {
+                super.onConnectionEvent(connection, event, extras);
+                callbackInvoker.invoke(connection, event, extras);
+            }
+        };
+        mRemoteConnectionObject.registerCallback(callback, handler);
+        Bundle extras = new Bundle();
+        extras.putString(TelecomManager.EXTRA_CALL_DISCONNECT_MESSAGE, "Test");
+        mRemoteConnection.sendConnectionEvent(Connection.EVENT_CALL_PULL_FAILED, extras);
+        callbackInvoker.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
+        assertEquals(mRemoteConnectionObject, callbackInvoker.getArgs(0)[0]);
+        assertEquals(Connection.EVENT_CALL_PULL_FAILED, callbackInvoker.getArgs(0)[1]);
+        assertTrue(areBundlesEqual(extras, (Bundle) callbackInvoker.getArgs(0)[2]));
+        mRemoteConnectionObject.unregisterCallback(callback);
     }
 
     public void testRemoteConnectionCallbacks_Disconnect() {
@@ -559,6 +621,23 @@
         mRemoteConnectionObject.unregisterCallback(callback);
     }
 
+    /**
+     * Verifies that a call to {@link RemoteConnection#pullExternalCall()} is proxied to
+     * {@link Connection#onPullExternalCall()}.
+     */
+    public void testRemoteConnectionCallbacks_PullExternalCall() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        Handler handler = setupRemoteConnectionCallbacksTest();
+
+        InvokeCounter counter =
+                mRemoteConnection.getInvokeCounter(MockConnection.ON_PULL_EXTERNAL_CALL);
+        mRemoteConnectionObject.pullExternalCall();
+        counter.waitForCount(1);
+    }
+
     public void testRemoteConnectionCallbacks_Destroy() {
         if (!mShouldTestTelecom) {
             return;
@@ -1106,6 +1185,8 @@
                 remoteConnection.getCallerDisplayNamePresentation());
         assertEquals(connection.getConnectionCapabilities(),
                 remoteConnection.getConnectionCapabilities());
+        assertEquals(connection.getConnectionProperties(),
+                remoteConnection.getConnectionProperties());
         assertEquals(connection.getDisconnectCause(), remoteConnection.getDisconnectCause());
         assertEquals(connection.getExtras(), remoteConnection.getExtras());
         assertEquals(connection.getStatusHints(), remoteConnection.getStatusHints());
diff --git a/tests/tests/text/src/android/text/cts/BoringLayoutTest.java b/tests/tests/text/src/android/text/cts/BoringLayoutTest.java
index 36d2f93..13465ae 100644
--- a/tests/tests/text/src/android/text/cts/BoringLayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/BoringLayoutTest.java
@@ -82,11 +82,10 @@
 
     private void verifyMultAddScale(float spacingMult, float spacingAdd) {
         final int height = METRICS_BOTTOM - METRICS_TOP;
-        final int bottomPadding = METRICS_BOTTOM - METRICS_DESCENT;
 
         BoringLayout boringLayout = makeBoringLayout(spacingMult, spacingAdd);
         assertEquals(height, boringLayout.getHeight());
-        assertEquals(height + bottomPadding + METRICS_TOP, boringLayout.getLineDescent(0));
+        assertEquals(height + METRICS_TOP, boringLayout.getLineDescent(0));
     }
 
     public void testScale() {
@@ -172,10 +171,8 @@
     }
 
     public void testGetLineDescent_withIncludePadding() {
-        final int bottomPadding = METRICS_BOTTOM - METRICS_DESCENT;
         final int height = METRICS_BOTTOM - METRICS_TOP;
-        assertEquals(height + METRICS_TOP + bottomPadding,
-                mBoringLayout.getLineDescent(0));
+        assertEquals(height + METRICS_TOP, mBoringLayout.getLineDescent(0));
     }
 
     public void testGetLineDescent_withoutIncludePadding() {
diff --git a/tests/tests/tv/AndroidManifest.xml b/tests/tests/tv/AndroidManifest.xml
index 7acfc94..cc64363 100644
--- a/tests/tests/tv/AndroidManifest.xml
+++ b/tests/tests/tv/AndroidManifest.xml
@@ -85,6 +85,16 @@
                        android:resource="@xml/stub_tv_input_service" />
         </service>
 
+        <service android:name="android.media.tv.cts.TvInputServiceTest$FaultyTvInputService"
+                 android:permission="android.permission.BIND_TV_INPUT"
+                 android:process=":faultyTvInputService">
+            <intent-filter>
+                <action android:name="android.media.tv.TvInputService" />
+            </intent-filter>
+            <meta-data android:name="android.media.tv.input"
+                       android:resource="@xml/stub_tv_input_service" />
+        </service>
+
         <service android:name="android.media.tv.cts.HardwareSessionTest$HardwareProxyTvInputService"
                  android:permission="android.permission.BIND_TV_INPUT">
             <intent-filter>
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java b/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
index a821d97..9b60967 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
@@ -32,6 +32,7 @@
 import android.media.tv.cts.TvInputServiceTest.CountingTvInputService.CountingRecordingSession;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Process;
 import android.os.SystemClock;
 import android.test.ActivityInstrumentationTestCase2;
 import android.view.InputDevice;
@@ -65,6 +66,7 @@
     private Instrumentation mInstrumentation;
     private TvInputManager mManager;
     private TvInputInfo mStubInfo;
+    private TvInputInfo mFaultyStubInfo;
     private final StubCallback mCallback = new StubCallback();
     private final StubTimeShiftPositionCallback mTimeShiftPositionCallback =
             new StubTimeShiftPositionCallback();
@@ -177,6 +179,11 @@
         for (TvInputInfo info : mManager.getTvInputList()) {
             if (info.getServiceInfo().name.equals(CountingTvInputService.class.getName())) {
                 mStubInfo = info;
+            }
+            if (info.getServiceInfo().name.equals(FaultyTvInputService.class.getName())) {
+                mFaultyStubInfo = info;
+            }
+            if (mStubInfo != null && mFaultyStubInfo != null) {
                 break;
             }
         }
@@ -233,13 +240,16 @@
             return;
         }
         verifyCommandTuneForRecording();
+        verifyCallbackConnectionFailed();
         verifyCommandTuneForRecordingWithBundle();
         verifyCallbackTuned();
         verifyCommandStartRecording();
         verifyCommandStopRecording();
+        verifyCommandSendAppPrivateCommandForRecording();
         verifyCallbackRecordingStopped();
         verifyCallbackError();
         verifyCommandRelease();
+        verifyCallbackDisconnected();
     }
 
     public void verifyCommandTuneForRecording() {
@@ -263,7 +273,7 @@
             @Override
             protected boolean check() {
                 CountingRecordingSession session = CountingTvInputService.sRecordingSession;
-                return session != null && session.mTuneCount > 0;
+                return session != null && session.mTuneWithBundleCount > 0;
             }
         }.run();
     }
@@ -304,6 +314,20 @@
         }.run();
     }
 
+    public void verifyCommandSendAppPrivateCommandForRecording() {
+        resetCounts();
+        String action = "android.media.tv.cts.TvInputServiceTest.privateCommand";
+        mTvRecordingClient.sendAppPrivateCommand(action, null);
+        new PollingCheck(TIME_OUT) {
+            @Override
+            protected boolean check() {
+                CountingRecordingSession session = CountingTvInputService.sRecordingSession;
+                return session != null && session.mAppPrivateCommandCount > 0;
+            }
+        }.run();
+    }
+
+
     public void verifyCallbackTuned() {
         resetCounts();
         CountingRecordingSession session = CountingTvInputService.sRecordingSession;
@@ -345,16 +369,26 @@
         }.run();
     }
 
-    public void verifyCommandSendAppPrivateCommand() {
+    public void verifyCallbackConnectionFailed() {
         resetCounts();
-        String action = "android.media.tv.cts.TvInputServiceTest.privateCommand";
-        mTvView.sendAppPrivateCommand(action, null);
-        mInstrumentation.waitForIdleSync();
+        Uri fakeChannelUri = TvContract.buildChannelUri(0);
+        mTvRecordingClient.tune("invalid_input_id", fakeChannelUri);
         new PollingCheck(TIME_OUT) {
             @Override
             protected boolean check() {
-                CountingSession session = CountingTvInputService.sSession;
-                return session != null && session.mSendAppPrivateCommand > 0;
+                return mRecordingCallback.mConnectionFailedCount > 0;
+            }
+        }.run();
+    }
+
+    public void verifyCallbackDisconnected() {
+        resetCounts();
+        Uri fakeChannelUri = TvContract.buildChannelUri(0);
+        mTvRecordingClient.tune(mFaultyStubInfo.getId(), fakeChannelUri);
+        new PollingCheck(TIME_OUT) {
+            @Override
+            protected boolean check() {
+                return mRecordingCallback.mDisconnectedCount > 0;
             }
         }.run();
     }
@@ -382,7 +416,7 @@
             @Override
             protected boolean check() {
                 CountingSession session = CountingTvInputService.sSession;
-                return session != null && session.mTuneCount > 0;
+                return session != null && session.mTuneWithBundleCount > 0;
             }
         }.run();
     }
@@ -613,6 +647,20 @@
         }.run();
     }
 
+    public void verifyCommandSendAppPrivateCommand() {
+        resetCounts();
+        String action = "android.media.tv.cts.TvInputServiceTest.privateCommand";
+        mTvView.sendAppPrivateCommand(action, null);
+        mInstrumentation.waitForIdleSync();
+        new PollingCheck(TIME_OUT) {
+            @Override
+            protected boolean check() {
+                CountingSession session = CountingTvInputService.sSession;
+                return session != null && session.mAppPrivateCommandCount > 0;
+            }
+        }.run();
+    }
+
     public void verifyCallbackChannelRetuned() {
         resetCounts();
         CountingSession session = CountingTvInputService.sSession;
@@ -792,8 +840,8 @@
         }
 
         public static class CountingSession extends Session {
-            public volatile int mSendAppPrivateCommand;
             public volatile int mTuneCount;
+            public volatile int mTuneWithBundleCount;
             public volatile int mSetStreamVolumeCount;
             public volatile int mSetCaptionEnabledCount;
             public volatile int mSelectTrackCount;
@@ -813,14 +861,15 @@
             public volatile int mTimeShiftPlayCount;
             public volatile long mTimeShiftGetCurrentPositionCount;
             public volatile long mTimeShiftGetStartPositionCount;
+            public volatile int mAppPrivateCommandCount;
 
             CountingSession(Context context) {
                 super(context);
             }
 
             public void resetCounts() {
-                mSendAppPrivateCommand = 0;
                 mTuneCount = 0;
+                mTuneWithBundleCount = 0;
                 mSetStreamVolumeCount = 0;
                 mSetCaptionEnabledCount = 0;
                 mSelectTrackCount = 0;
@@ -840,11 +889,7 @@
                 mTimeShiftPlayCount = 0;
                 mTimeShiftGetCurrentPositionCount = 0;
                 mTimeShiftGetStartPositionCount = 0;
-            }
-
-            @Override
-            public void onAppPrivateCommand(String action, Bundle data) {
-                mSendAppPrivateCommand++;
+                mAppPrivateCommandCount = 0;
             }
 
             @Override
@@ -863,6 +908,15 @@
             }
 
             @Override
+            public boolean onTune(Uri channelUri, Bundle data) {
+                mTuneWithBundleCount++;
+                // Also calls {@link #onTune(Uri)} since it will never be called if the
+                // implementation overrides {@link #onTune(Uri, Bundle)}.
+                onTune(channelUri);
+                return false;
+            }
+
+            @Override
             public void onSetStreamVolume(float volume) {
                 mSetStreamVolumeCount++;
             }
@@ -965,13 +1019,20 @@
             public void onOverlayViewSizeChanged(int width, int height) {
                 mOverlayViewSizeChangedCount++;
             }
+
+            @Override
+            public void onAppPrivateCommand(String action, Bundle data) {
+                mAppPrivateCommandCount++;
+            }
         }
 
         public static class CountingRecordingSession extends RecordingSession {
             public volatile int mTuneCount;
+            public volatile int mTuneWithBundleCount;
             public volatile int mReleaseCount;
             public volatile int mStartRecordingCount;
             public volatile int mStopRecordingCount;
+            public volatile int mAppPrivateCommandCount;
 
             CountingRecordingSession(Context context) {
                 super(context);
@@ -979,9 +1040,11 @@
 
             public void resetCounts() {
                 mTuneCount = 0;
+                mTuneWithBundleCount = 0;
                 mReleaseCount = 0;
                 mStartRecordingCount = 0;
                 mStopRecordingCount = 0;
+                mAppPrivateCommandCount = 0;
             }
 
             @Override
@@ -990,6 +1053,14 @@
             }
 
             @Override
+            public void onTune(Uri channelUri, Bundle data) {
+                mTuneWithBundleCount++;
+                // Also calls {@link #onTune(Uri)} since it will never be called if the
+                // implementation overrides {@link #onTune(Uri, Bundle)}.
+                onTune(channelUri);
+            }
+
+            @Override
             public void onRelease() {
                 mReleaseCount++;
             }
@@ -1003,6 +1074,11 @@
             public void onStopRecording() {
                 mStopRecordingCount++;
             }
+
+            @Override
+            public void onAppPrivateCommand(String action, Bundle data) {
+                mAppPrivateCommandCount++;
+            }
         }
     }
 
@@ -1010,6 +1086,8 @@
         private int mTunedCount;
         private int mRecordingStoppedCount;
         private int mErrorCount;
+        private int mConnectionFailedCount;
+        private int mDisconnectedCount;
 
         @Override
         public void onTuned(Uri channelUri) {
@@ -1026,10 +1104,49 @@
             mErrorCount++;
         }
 
+        @Override
+        public void onConnectionFailed(String inputId) {
+            mConnectionFailedCount++;
+        }
+
+        @Override
+        public void onDisconnected(String inputId) {
+            mDisconnectedCount++;
+        }
+
         public void resetCounts() {
             mTunedCount = 0;
             mRecordingStoppedCount = 0;
             mErrorCount = 0;
+            mConnectionFailedCount = 0;
+            mDisconnectedCount = 0;
+        }
+    }
+
+    public static class FaultyTvInputService extends StubTvInputService {
+        @Override
+        public RecordingSession onCreateRecordingSession(String inputId) {
+            return new FaultyRecordingSession(this);
+        }
+
+        public static class FaultyRecordingSession extends RecordingSession {
+            FaultyRecordingSession(Context context) {
+                super(context);
+            }
+
+            @Override
+            public void onTune(Uri channelUri) {
+                Process.killProcess(android.os.Process.myPid());
+            }
+
+            @Override
+            public void onStartRecording(Uri programHint) { }
+
+            @Override
+            public void onStopRecording() { }
+
+            @Override
+            public void onRelease() { }
         }
     }
 }
diff --git a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
index 0d57e4e..9d33a0a 100755
--- a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
+++ b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
@@ -275,21 +275,11 @@
         }
     }
 
-    public void testChangingFlags_shouldThrowException() {
-        getInstrumentation().getUiAutomation();
-        try {
-            getInstrumentation()
-                    .getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
-            fail("Expected exception when changing UiAutomation flags");
-        } catch (RuntimeException e) {
-        }
-    }
-
     public void testDontSuppressAccessibility_canStartA11yService() throws IOException,
             InterruptedException {
         turnAccessibilityOff();
         try {
-            UiAutomation uiAutomation = getInstrumentation()
+            getInstrumentation()
                     .getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
             enableAccessibilityService();
             assertTrue(UiAutomationTestA11yService.sConnectedInstance.isConnected());
@@ -333,6 +323,25 @@
         }
     }
 
+    public void testServiceSupressingA11yServices_a11yServiceStartsWhenFlagsChange()
+            throws IOException, InterruptedException {
+        turnAccessibilityOff();
+        try {
+            getInstrumentation()
+                    .getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
+            enableAccessibilityService();
+            getInstrumentation().getUiAutomation();
+            // We verify above that the connection is broken here. Make sure we see a new one
+            // after we change the flags
+            UiAutomationTestA11yService.sConnectedInstance = null;
+            getInstrumentation()
+                    .getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
+            waitForAccessibilityServiceToStart();
+        } finally {
+            turnAccessibilityOff();
+        }
+    }
+
     private void scrollListView(UiAutomation uiAutomation, final ListView listView,
             final int position) throws TimeoutException {
         getInstrumentation().runOnMainSync(new Runnable() {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java
index d0820e2..a2f0305 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java
@@ -16,7 +16,6 @@
 package android.uirendering.cts.testclasses;
 
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.PaintFlagsDrawFilter;
@@ -112,18 +111,15 @@
         final Paint paint = new Paint(filterEnum.equals(FilterEnum.ADD_FILTER) ?
                 0 : Paint.FILTER_BITMAP_FLAG);
 
-        CanvasClient canvasClient = new CanvasClient() {
-            @Override
-            public void draw(Canvas canvas, int width, int height) {
-                canvas.scale(1.0f * width / gridWidth, 1.0f * height / gridWidth);
-                if (filterEnum.equals(FilterEnum.ADD_FILTER)) {
-                    canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG));
-                } else if (filterEnum.equals(FilterEnum.REMOVE_FILTER)) {
-                    canvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0));
-                }
-                canvas.drawBitmap(scaleUp ? mSmallGridBitmap : mBigGridBitmap, 0, 0, paint);
-                canvas.setDrawFilter(null);
+        CanvasClient canvasClient = (canvas, width, height) -> {
+            canvas.scale(1.0f * width / gridWidth, 1.0f * height / gridWidth);
+            if (filterEnum.equals(FilterEnum.ADD_FILTER)) {
+                canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.FILTER_BITMAP_FLAG));
+            } else if (filterEnum.equals(FilterEnum.REMOVE_FILTER)) {
+                canvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0));
             }
+            canvas.drawBitmap(scaleUp ? mSmallGridBitmap : mBigGridBitmap, 0, 0, paint);
+            canvas.setDrawFilter(null);
         };
         createTest()
                 .addCanvasClient(canvasClient)
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
index 38d884d..1e7a832 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
@@ -22,7 +22,6 @@
 import android.graphics.Region;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
-import android.uirendering.cts.testinfrastructure.CanvasClient;
 import org.junit.Test;
 
 import static org.junit.Assert.assertFalse;
@@ -39,17 +38,14 @@
     @Test
     public void testClipRectReturnValues() {
         createTest()
-                .addCanvasClient(new CanvasClient() {
-                    @Override
-                    public void draw(Canvas canvas, int width, int height) {
-                        canvas.save();
-                        boolean isNonEmpty = canvas.clipRect(0, 0, 20, 20);
-                        assertTrue("clip state should be non empty", isNonEmpty);
+                .addCanvasClient((canvas, width, height) -> {
+                    canvas.save();
+                    boolean isNonEmpty = canvas.clipRect(0, 0, 20, 20);
+                    assertTrue("clip state should be non empty", isNonEmpty);
 
-                        isNonEmpty = canvas.clipRect(0, 40, 20, 60);
-                        assertFalse("clip state should be empty", isNonEmpty);
-                        canvas.restore();
-                    }
+                    isNonEmpty = canvas.clipRect(0, 40, 20, 60);
+                    assertFalse("clip state should be empty", isNonEmpty);
+                    canvas.restore();
                 })
                 .runWithoutVerification();
     }
@@ -57,32 +53,29 @@
     @Test
     public void testClipRegionReturnValues() {
         createTest()
-                .addCanvasClient(new CanvasClient() {
-                    @Override
-                    public void draw(Canvas canvas, int width, int height) {
-                        canvas.save();
-                        RectF clipRectF = new RectF(0, 0, 20, 20);
+                .addCanvasClient((canvas, width, height) -> {
+                    canvas.save();
+                    RectF clipRectF = new RectF(0, 0, 20, 20);
 
-                        assertFalse(canvas.quickReject(0, 0, 20, 20, Canvas.EdgeType.BW));
-                        if (!canvas.isHardwareAccelerated()) {
-                            // SW canvas may not be in View space, so we offset the clipping region
-                            // so it will operate within the canvas client's window.
-                            // (Currently, this isn't necessary, since SW layer size == draw area)
-                            canvas.getMatrix().mapRect(clipRectF);
-                        }
-
-                        Region rectRegion = new Region();
-                        rectRegion.set((int) clipRectF.left, (int) clipRectF.top,
-                                (int) clipRectF.right, (int) clipRectF.bottom);
-
-                        boolean isNonEmpty = canvas.clipRegion(rectRegion);
-                        assertTrue("clip state should be non empty", isNonEmpty);
-
-                        // Note: we don't test that non-intersecting clip regions empty the clip,
-                        // For region clipping, the impl is allowed to return true conservatively
-                        // in many cases.
-                        canvas.restore();
+                    assertFalse(canvas.quickReject(0, 0, 20, 20, Canvas.EdgeType.BW));
+                    if (!canvas.isHardwareAccelerated()) {
+                        // SW canvas may not be in View space, so we offset the clipping region
+                        // so it will operate within the canvas client's window.
+                        // (Currently, this isn't necessary, since SW layer size == draw area)
+                        canvas.getMatrix().mapRect(clipRectF);
                     }
+
+                    Region rectRegion = new Region();
+                    rectRegion.set((int) clipRectF.left, (int) clipRectF.top,
+                            (int) clipRectF.right, (int) clipRectF.bottom);
+
+                    boolean isNonEmpty = canvas.clipRegion(rectRegion);
+                    assertTrue("clip state should be non empty", isNonEmpty);
+
+                    // Note: we don't test that non-intersecting clip regions empty the clip,
+                    // For region clipping, the impl is allowed to return true conservatively
+                    // in many cases.
+                    canvas.restore();
                 })
                 .runWithoutVerification();
     }
@@ -90,40 +83,34 @@
     @Test
     public void testClipPathReturnValues() {
         createTest()
-                .addCanvasClient(new CanvasClient() {
-                    @Override
-                    public void draw(Canvas canvas, int width, int height) {
-                        canvas.save();
-                        Path rectPath = new Path();
-                        rectPath.addRect(0, 0, 20, 20, Path.Direction.CW);
+                .addCanvasClient((canvas, width, height) -> {
+                    canvas.save();
+                    Path rectPath = new Path();
+                    rectPath.addRect(0, 0, 20, 20, Path.Direction.CW);
 
-                        boolean isNonEmpty = canvas.clipPath(rectPath);
-                        assertTrue("clip state should be non empty", isNonEmpty);
+                    boolean isNonEmpty = canvas.clipPath(rectPath);
+                    assertTrue("clip state should be non empty", isNonEmpty);
 
-                        rectPath.offset(0, 40);
-                        isNonEmpty = canvas.clipPath(rectPath);
-                        assertFalse("clip state should be empty", isNonEmpty);
-                        canvas.restore();
-                    }
+                    rectPath.offset(0, 40);
+                    isNonEmpty = canvas.clipPath(rectPath);
+                    assertFalse("clip state should be empty", isNonEmpty);
+                    canvas.restore();
                 })
                 .runWithoutVerification();
     }
     @Test
     public void testQuickReject() {
         createTest()
-                .addCanvasClient(new CanvasClient() {
-                    @Override
-                    public void draw(Canvas canvas, int width, int height) {
-                        canvas.save();
-                        canvas.clipRect(0, 0, 20, 20);
+                .addCanvasClient((canvas, width, height) -> {
+                    canvas.save();
+                    canvas.clipRect(0, 0, 20, 20);
 
-                        // not rejected!
-                        assertFalse(canvas.quickReject(0, 0, 20, 20, Canvas.EdgeType.BW));
+                    // not rejected!
+                    assertFalse(canvas.quickReject(0, 0, 20, 20, Canvas.EdgeType.BW));
 
-                        // rejected!
-                        assertTrue(canvas.quickReject(0, 40, 20, 60, Canvas.EdgeType.BW));
-                        canvas.restore();
-                    }
+                    // rejected!
+                    assertTrue(canvas.quickReject(0, 40, 20, 60, Canvas.EdgeType.BW));
+                    canvas.restore();
                 })
                 .runWithoutVerification();
     }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
index bf68f3e..2a2599b 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
@@ -16,7 +16,6 @@
 
 package android.uirendering.cts.testclasses;
 
-import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
@@ -28,7 +27,6 @@
 import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
 import android.uirendering.cts.bitmapverifiers.RectVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
-import android.uirendering.cts.testinfrastructure.CanvasClient;
 import android.uirendering.cts.R;
 import org.junit.Test;
 
@@ -40,14 +38,11 @@
     public void testBlueRect() {
         final Rect rect = new Rect(10, 10, 80, 80);
         createTest()
-                .addCanvasClient(new CanvasClient() {
-                    @Override
-                    public void draw(Canvas canvas, int width, int height) {
-                        Paint p = new Paint();
-                        p.setAntiAlias(false);
-                        p.setColor(Color.BLUE);
-                        canvas.drawRect(rect, p);
-                    }
+                .addCanvasClient((canvas, width, height) -> {
+                    Paint p = new Paint();
+                    p.setAntiAlias(false);
+                    p.setColor(Color.BLUE);
+                    canvas.drawRect(rect, p);
                 })
                 .runWithVerifier(new RectVerifier(Color.WHITE, Color.BLUE, rect));
     }
@@ -55,16 +50,13 @@
     @Test
     public void testPoints() {
         createTest()
-                .addCanvasClient(new CanvasClient() {
-                    @Override
-                    public void draw(Canvas canvas, int width, int height) {
-                        Paint p = new Paint();
-                        p.setAntiAlias(false);
-                        p.setStrokeWidth(1f);
-                        p.setColor(Color.BLACK);
-                        for (int i = 0; i < 10; i++) {
-                            canvas.drawPoint(i * 10, i * 10, p);
-                        }
+                .addCanvasClient((canvas, width, height) -> {
+                    Paint p = new Paint();
+                    p.setAntiAlias(false);
+                    p.setStrokeWidth(1f);
+                    p.setColor(Color.BLACK);
+                    for (int i = 0; i < 10; i++) {
+                        canvas.drawPoint(i * 10, i * 10, p);
                     }
                 })
                 .runWithComparer(mExactComparer);
@@ -73,17 +65,14 @@
     @Test
     public void testBlackRectWithStroke() {
         createTest()
-                .addCanvasClient(new CanvasClient() {
-                    @Override
-                    public void draw(Canvas canvas, int width, int height) {
-                        Paint p = new Paint();
-                        p.setColor(Color.RED);
-                        canvas.drawRect(0, 0, ActivityTestBase.TEST_WIDTH,
-                                ActivityTestBase.TEST_HEIGHT, p);
-                        p.setColor(Color.BLACK);
-                        p.setStrokeWidth(5);
-                        canvas.drawRect(10, 10, 80, 80, p);
-                    }
+                .addCanvasClient((canvas, width, height) -> {
+                    Paint p = new Paint();
+                    p.setColor(Color.RED);
+                    canvas.drawRect(0, 0, ActivityTestBase.TEST_WIDTH,
+                            ActivityTestBase.TEST_HEIGHT, p);
+                    p.setColor(Color.BLACK);
+                    p.setStrokeWidth(5);
+                    canvas.drawRect(10, 10, 80, 80, p);
                 })
                 .runWithComparer(mExactComparer);
     }
@@ -91,15 +80,12 @@
     @Test
     public void testBlackLineOnGreenBack() {
         createTest()
-                .addCanvasClient(new CanvasClient() {
-                    @Override
-                    public void draw(Canvas canvas, int width, int height) {
-                        canvas.drawColor(Color.GREEN);
-                        Paint p = new Paint();
-                        p.setColor(Color.BLACK);
-                        p.setStrokeWidth(10);
-                        canvas.drawLine(0, 0, 50, 0, p);
-                    }
+                .addCanvasClient((canvas, width, height) -> {
+                    canvas.drawColor(Color.GREEN);
+                    Paint p = new Paint();
+                    p.setColor(Color.BLACK);
+                    p.setStrokeWidth(10);
+                    canvas.drawLine(0, 0, 50, 0, p);
                 })
                 .runWithComparer(mExactComparer);
     }
@@ -107,14 +93,11 @@
     @Test
     public void testDrawRedRectOnBlueBack() {
         createTest()
-                .addCanvasClient(new CanvasClient() {
-                    @Override
-                    public void draw(Canvas canvas, int width, int height) {
-                        canvas.drawColor(Color.BLUE);
-                        Paint p = new Paint();
-                        p.setColor(Color.RED);
-                        canvas.drawRect(10, 10, 40, 40, p);
-                    }
+                .addCanvasClient((canvas, width, height) -> {
+                    canvas.drawColor(Color.BLUE);
+                    Paint p = new Paint();
+                    p.setColor(Color.RED);
+                    canvas.drawRect(10, 10, 40, 40, p);
                 })
                 .runWithComparer(mExactComparer);
     }
@@ -122,17 +105,14 @@
     @Test
     public void testDrawLine() {
         createTest()
-                .addCanvasClient(new CanvasClient() {
-                    @Override
-                    public void draw(Canvas canvas, int width, int height) {
-                        Paint p = new Paint();
-                        canvas.drawColor(Color.WHITE);
-                        p.setColor(Color.BLACK);
-                        float[] pts = {
-                                0, 0, 80, 80, 80, 0, 0, 80, 40, 50, 60, 50
-                        };
-                        canvas.drawLines(pts, p);
-                    }
+                .addCanvasClient((canvas, width, height) -> {
+                    Paint p = new Paint();
+                    canvas.drawColor(Color.WHITE);
+                    p.setColor(Color.BLACK);
+                    float[] pts = {
+                            0, 0, 80, 80, 80, 0, 0, 80, 40, 50, 60, 50
+                    };
+                    canvas.drawLines(pts, p);
                 })
                 .runWithComparer(mExactComparer);
     }
@@ -140,12 +120,7 @@
     @Test
     public void testDrawWhiteScreen() {
         createTest()
-                .addCanvasClient(new CanvasClient() {
-                    @Override
-                    public void draw(Canvas canvas, int width, int height) {
-                        canvas.drawColor(Color.WHITE);
-                    }
-                })
+                .addCanvasClient((canvas, width, height) -> canvas.drawColor(Color.WHITE))
                 .runWithComparer(mExactComparer);
     }
 
@@ -153,15 +128,12 @@
     public void testBasicText() {
         final String testString = "THIS IS A TEST";
         createTest()
-                .addCanvasClient(new CanvasClient() {
-                    @Override
-                    public void draw(Canvas canvas, int width, int height) {
-                        Paint p = new Paint();
-                        canvas.drawColor(Color.BLACK);
-                        p.setColor(Color.WHITE);
-                        p.setStrokeWidth(5);
-                        canvas.drawText(testString, 30, 50, p);
-                    }
+                .addCanvasClient((canvas, width, height) -> {
+                    Paint p = new Paint();
+                    canvas.drawColor(Color.BLACK);
+                    p.setColor(Color.WHITE);
+                    p.setStrokeWidth(5);
+                    canvas.drawText(testString, 30, 50, p);
                 })
                 .runWithComparer(mExactComparer);
     }
@@ -169,12 +141,9 @@
     @Test
     public void testBasicColorXfermode() {
         createTest()
-                .addCanvasClient(new CanvasClient() {
-                    @Override
-                    public void draw(Canvas canvas, int width, int height) {
-                        canvas.drawColor(Color.GRAY);
-                        canvas.drawColor(Color.BLUE, PorterDuff.Mode.MULTIPLY);
-                    }
+                .addCanvasClient((canvas, width, height) -> {
+                    canvas.drawColor(Color.GRAY);
+                    canvas.drawColor(Color.BLUE, PorterDuff.Mode.MULTIPLY);
                 })
                 .runWithComparer(mExactComparer);
     }
@@ -189,21 +158,13 @@
                 new Rect(10, 10, 80, 80));
 
         createTest()
-                .addCanvasClient(new CanvasClient() {
-                    @Override
-                    public void draw(Canvas canvas, int width, int height) {
-                        canvas.drawColor(Color.WHITE);
-                        Paint p = new Paint();
-                        p.setColor(Color.BLUE);
-                        canvas.drawRect(10, 10, 80, 80, p);
-                    }
+                .addCanvasClient((canvas, width, height) -> {
+                    canvas.drawColor(Color.WHITE);
+                    Paint p = new Paint();
+                    p.setColor(Color.BLUE);
+                    canvas.drawRect(10, 10, 80, 80, p);
                 })
-                .addCanvasClient(new CanvasClient() {
-                    @Override
-                    public void draw(Canvas canvas, int width, int height) {
-                        ninePatchDrawable.draw(canvas);
-                    }
-                })
+                .addCanvasClient((canvas, width, height) -> ninePatchDrawable.draw(canvas))
                 .addLayout(R.layout.blue_padded_square, null)
                 .runWithVerifier(verifier);
     }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
index 738dcfb..73779d6 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
@@ -53,18 +53,15 @@
 
         final Typeface typeface = Typeface.create(family, style);
         createTest()
-                .addCanvasClient(new CanvasClient() {
-                    @Override
-                    public void draw(Canvas canvas, int width, int height) {
-                        Paint p = new Paint();
-                        p.setAntiAlias(true);
-                        p.setColor(Color.BLACK);
-                        p.setTextSize(26);
-                        p.setTypeface(typeface);
-                        canvas.drawText(sTestString1, 1, 20, p);
-                        canvas.drawText(sTestString2, 1, 50, p);
-                        canvas.drawText(sTestString3, 1, 80, p);
-                    }
+                .addCanvasClient((canvas, width, height) -> {
+                    Paint p = new Paint();
+                    p.setAntiAlias(true);
+                    p.setColor(Color.BLACK);
+                    p.setTextSize(26);
+                    p.setTypeface(typeface);
+                    canvas.drawText(sTestString1, 1, 20, p);
+                    canvas.drawText(sTestString2, 1, 50, p);
+                    canvas.drawText(sTestString3, 1, 80, p);
                 })
                 .runWithVerifier(new GoldenImageVerifier(goldenBitmap, comparer));
     }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
index c070b96..212e666 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
@@ -19,7 +19,6 @@
 import android.test.suitebuilder.annotation.MediumTest;
 import android.uirendering.cts.R;
 
-import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.uirendering.cts.bitmapcomparers.BitmapComparer;
@@ -49,11 +48,8 @@
      */
     @Test
     public void testRenderSpecIsolation() {
-        CanvasClient canvasClient = new CanvasClient() {
-            @Override
-            public void draw(Canvas canvas, int width, int height) {
-                canvas.drawColor(canvas.isHardwareAccelerated() ? Color.BLACK : Color.WHITE);
-            }
+        CanvasClient canvasClient = (canvas, width, height) -> {
+            canvas.drawColor(canvas.isHardwareAccelerated() ? Color.BLACK : Color.WHITE);
         };
         BitmapComparer inverseComparer = new BitmapComparer() {
             @Override
@@ -75,12 +71,7 @@
     @Test
     public void testViewInitializer() {
         final Rect clipRect = new Rect(0, 0, 50, 50);
-        ViewInitializer viewInitializer = new ViewInitializer() {
-            @Override
-            public void initializeView(View view) {
-                view.setClipBounds(clipRect);
-            }
-        };
+        ViewInitializer viewInitializer = view -> view.setClipBounds(clipRect);
         createTest()
                 .addLayout(R.layout.simple_red_layout, viewInitializer)
                 .runWithVerifier(new RectVerifier(Color.WHITE, Color.RED, clipRect));
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
index 30dbb03..53112d6 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
@@ -43,17 +43,14 @@
         @ColorInt
         final int expectedColor = Color.rgb(255, 191, 191);
         createTest()
-                .addLayout(R.layout.simple_red_layout, new ViewInitializer() {
-                    @Override
-                    public void initializeView(View view) {
-                        // reduce alpha by 50%
-                        Paint paint = new Paint();
-                        paint.setAlpha(128);
-                        view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
+                .addLayout(R.layout.simple_red_layout, (ViewInitializer) view -> {
+                    // reduce alpha by 50%
+                    Paint paint = new Paint();
+                    paint.setAlpha(128);
+                    view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
 
-                        // reduce alpha by another 50% (ensuring two alphas combine correctly)
-                        view.setAlpha(0.5f);
-                    }
+                    // reduce alpha by another 50% (ensuring two alphas combine correctly)
+                    view.setAlpha(0.5f);
                 })
                 .runWithVerifier(new ColorVerifier(expectedColor));
     }
@@ -65,15 +62,12 @@
         @ColorInt
         final int expectedColor = Color.rgb(54, 54, 54);
         createTest()
-                .addLayout(R.layout.simple_red_layout, new ViewInitializer() {
-                    @Override
-                    public void initializeView(View view) {
-                        Paint paint = new Paint();
-                        ColorMatrix desatMatrix = new ColorMatrix();
-                        desatMatrix.setSaturation(0.0f);
-                        paint.setColorFilter(new ColorMatrixColorFilter(desatMatrix));
-                        view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
-                    }
+                .addLayout(R.layout.simple_red_layout, (ViewInitializer) view -> {
+                    Paint paint = new Paint();
+                    ColorMatrix desatMatrix = new ColorMatrix();
+                    desatMatrix.setSaturation(0.0f);
+                    paint.setColorFilter(new ColorMatrixColorFilter(desatMatrix));
+                    view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
                 })
                 .runWithVerifier(new ColorVerifier(expectedColor));
     }
@@ -85,20 +79,17 @@
         @ColorInt
         final int expectedColor = Color.WHITE;
         createTest()
-                .addLayout(R.layout.simple_red_layout, new ViewInitializer() {
-                    @Override
-                    public void initializeView(View view) {
-                        Paint paint = new Paint();
-                        /* Note that when drawing in SW, we're blending within an otherwise empty
-                         * SW layer, as opposed to in the frame buffer (which has a white
-                         * background).
-                         *
-                         * For this reason we use just use DST, which just throws out the SRC
-                         * content, regardless of the DST alpha channel.
-                         */
-                        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST));
-                        view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
-                    }
+                .addLayout(R.layout.simple_red_layout, (ViewInitializer) view -> {
+                    Paint paint = new Paint();
+                    /* Note that when drawing in SW, we're blending within an otherwise empty
+                     * SW layer, as opposed to in the frame buffer (which has a white
+                     * background).
+                     *
+                     * For this reason we use just use DST, which just throws out the SRC
+                     * content, regardless of the DST alpha channel.
+                     */
+                    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST));
+                    view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
                 })
                 .runWithVerifier(new ColorVerifier(expectedColor));
     }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
index 03f5e89..7c8a301 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
@@ -40,57 +40,41 @@
 @MediumTest
 public class PathClippingTests extends ActivityTestBase {
     // draw circle with hole in it, with stroked circle
-    static final CanvasClient sTorusDrawCanvasClient = new CanvasClient() {
-        @Override
-        public String getDebugString() {
-            return "TorusDraw";
-        }
-
-        @Override
-        public void draw(Canvas canvas, int width, int height) {
-            Paint paint = new Paint();
-            paint.setAntiAlias(false);
-            paint.setColor(Color.BLUE);
-            paint.setStyle(Paint.Style.STROKE);
-            paint.setStrokeWidth(20);
-            canvas.drawCircle(30, 30, 40, paint);
-        }
+    static final CanvasClient sTorusDrawCanvasClient = (canvas, width, height) -> {
+        Paint paint = new Paint();
+        paint.setAntiAlias(false);
+        paint.setColor(Color.BLUE);
+        paint.setStyle(Paint.Style.STROKE);
+        paint.setStrokeWidth(20);
+        canvas.drawCircle(30, 30, 40, paint);
     };
 
     // draw circle with hole in it, by path operations + path clipping
-    static final CanvasClient sTorusClipCanvasClient = new CanvasClient() {
-        @Override
-        public String getDebugString() {
-            return "TorusClipDraw";
-        }
+    static final CanvasClient sTorusClipCanvasClient = (canvas, width, height) -> {
+        canvas.save();
 
-        @Override
-        public void draw(Canvas canvas, int width, int height) {
-            canvas.save();
+        Path path = new Path();
+        path.addCircle(30, 30, 50, Path.Direction.CW);
+        path.addCircle(30, 30, 30, Path.Direction.CCW);
 
-            Path path = new Path();
-            path.addCircle(30, 30, 50, Path.Direction.CW);
-            path.addCircle(30, 30, 30, Path.Direction.CCW);
+        canvas.clipPath(path);
+        canvas.drawColor(Color.BLUE);
 
-            canvas.clipPath(path);
-            canvas.drawColor(Color.BLUE);
-
-            canvas.restore();
-        }
+        canvas.restore();
     };
 
     @Test
     public void testCircleWithCircle() {
         createTest()
-                .addCanvasClient(sTorusDrawCanvasClient, false)
-                .addCanvasClient(sTorusClipCanvasClient)
+                .addCanvasClient("TorusDraw", sTorusDrawCanvasClient, false)
+                .addCanvasClient("TorusClip", sTorusClipCanvasClient)
                 .runWithComparer(new MSSIMComparer(0.90));
     }
 
     @Test
     public void testCircleWithPoints() {
         createTest()
-                .addCanvasClient(sTorusClipCanvasClient)
+                .addCanvasClient("TorusClip", sTorusClipCanvasClient)
                 .runWithVerifier(new SamplePointVerifier(
                         new Point[] {
                                 // inside of circle
@@ -112,17 +96,13 @@
     @Test
     public void testViewRotate() {
         createTest()
-                .addLayout(R.layout.blue_padded_layout, new ViewInitializer() {
-                    @Override
-                    public void initializeView(View view) {
-                        ViewGroup rootView = (ViewGroup) view;
-                        rootView.setClipChildren(true);
-                        View childView = rootView.getChildAt(0);
-                        childView.setPivotX(40);
-                        childView.setPivotY(40);
-                        childView.setRotation(45f);
-
-                    }
+                .addLayout(R.layout.blue_padded_layout, (ViewInitializer) view -> {
+                    ViewGroup rootView = (ViewGroup) view;
+                    rootView.setClipChildren(true);
+                    View childView = rootView.getChildAt(0);
+                    childView.setPivotX(40);
+                    childView.setPivotY(40);
+                    childView.setRotation(45f);
                 })
                 .runWithVerifier(new SamplePointVerifier(
                         new Point[] {
@@ -144,24 +124,21 @@
     @Test
     public void testTextClip() {
         createTest()
-                .addCanvasClient(new CanvasClient() {
-                    @Override
-                    public void draw(Canvas canvas, int width, int height) {
-                        canvas.save();
+                .addCanvasClient((canvas, width, height) -> {
+                    canvas.save();
 
-                        Path path = new Path();
-                        path.addCircle(0, 45, 45, Path.Direction.CW);
-                        path.addCircle(90, 45, 45, Path.Direction.CW);
-                        canvas.clipPath(path);
+                    Path path = new Path();
+                    path.addCircle(0, 45, 45, Path.Direction.CW);
+                    path.addCircle(90, 45, 45, Path.Direction.CW);
+                    canvas.clipPath(path);
 
-                        Paint paint = new Paint();
-                        paint.setAntiAlias(true);
-                        paint.setTextSize(90);
-                        paint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
-                        canvas.drawText("STRING", 0, 90, paint);
+                    Paint paint = new Paint();
+                    paint.setAntiAlias(true);
+                    paint.setTextSize(90);
+                    paint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
+                    canvas.drawText("STRING", 0, 90, paint);
 
-                        canvas.restore();
-                    }
+                    canvas.restore();
                 })
                 .runWithComparer(new MSSIMComparer(0.90));
     }
@@ -173,23 +150,17 @@
         }
         createTest()
                 // golden client - draw a simple non-AA circle
-                .addCanvasClient(new CanvasClient() {
-                    @Override
-                    public void draw(Canvas canvas, int width, int height) {
-                        Paint paint = new Paint();
-                        paint.setAntiAlias(false);
-                        paint.setColor(Color.BLUE);
-                        canvas.drawOval(0, 0, width, height, paint);
-                    }
+                .addCanvasClient((canvas, width, height) -> {
+                    Paint paint = new Paint();
+                    paint.setAntiAlias(false);
+                    paint.setColor(Color.BLUE);
+                    canvas.drawOval(0, 0, width, height, paint);
                 }, false)
                 // verify against solid color webview, clipped to its parent oval
-                .addLayout(R.layout.circle_clipped_webview, new ViewInitializer() {
-                    @Override
-                    public void initializeView(View view) {
-                        WebView webview = (WebView)view.findViewById(R.id.webview);
-                        assertNotNull(webview);
-                        webview.loadData("<body style=\"background-color:blue\">", null, null);
-                    }
+                .addLayout(R.layout.circle_clipped_webview, (ViewInitializer) view -> {
+                    WebView webview = (WebView)view.findViewById(R.id.webview);
+                    assertNotNull(webview);
+                    webview.loadData("<body style=\"background-color:blue\">", null, null);
                 })
                 .runWithComparer(new MSSIMComparer(0.95));
     }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PictureTest.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PictureTest.java
index 9c8f9ba..a2f3730 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PictureTest.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PictureTest.java
@@ -25,7 +25,6 @@
 import android.uirendering.cts.bitmapverifiers.ColorVerifier;
 import android.uirendering.cts.bitmapverifiers.RectVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
-import android.uirendering.cts.testinfrastructure.CanvasClient;
 import org.junit.Test;
 
 @MediumTest
@@ -38,8 +37,8 @@
         Paint pt = new Paint();
         pt.setColor(Color.GREEN);
         Picture pic = new Picture();
-        Canvas subcanvas = pic.beginRecording(ActivityTestBase.TEST_WIDTH,
-                                              ActivityTestBase.TEST_HEIGHT);
+        Canvas subcanvas = pic.beginRecording(
+                ActivityTestBase.TEST_WIDTH, ActivityTestBase.TEST_HEIGHT);
         subcanvas.drawRect(sRect, pt);
         pic.endRecording();
 
@@ -50,14 +49,11 @@
     public void testPictureRespectsClip() throws Exception {
         createTest()
             .addCanvasClient(
-                new CanvasClient() {
-                    @Override
-                    public void draw(Canvas canvas, int width, int height) {
+                    (canvas, width, height) -> {
                         Picture pic = greenSquare();
                         canvas.clipRect(sOffsetRect);
                         pic.draw(canvas);  // should be clipped out
                     }
-                }
             ).runWithVerifier(new ColorVerifier(Color.WHITE));
     }
 
@@ -65,14 +61,11 @@
     public void testPictureRespectsTranslate() throws Exception {
         createTest()
             .addCanvasClient(
-                new CanvasClient() {
-                    @Override
-                    public void draw(Canvas canvas, int width, int height) {
+                    (canvas, width, height) -> {
                         Picture pic = greenSquare();
                         canvas.translate(40, 0);
                         pic.draw(canvas);  // should be offset
                     }
-                }
             ).runWithVerifier(
                 new RectVerifier(Color.WHITE, Color.GREEN, sOffsetRect));
     }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
index f5f59b3..3f51bbe 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
@@ -108,23 +108,21 @@
         ResourceModifier.init(getActivity().getResources());
         // For each modification combination, we will get the CanvasClient associated with it and
         // from there execute a normal canvas test with that.
-        CanvasClient canvasClient = new CanvasClient() {
-            @Override
-            public void draw(Canvas canvas, int width, int height) {
-                Paint paint = new Paint();
-                modifierAccessor.modifyDrawing(canvas, paint);
-                if (drawOp != null) {
-                    drawOp.modifyDrawing(paint, canvas);
-                }
+        CanvasClient canvasClient = (canvas, width, height) -> {
+            Paint paint = new Paint();
+            modifierAccessor.modifyDrawing(canvas, paint);
+            if (drawOp != null) {
+                drawOp.modifyDrawing(paint, canvas);
             }
         };
 
         int index = 0;
         // Create the test cases with each combination
         do {
-            canvasClient.setDebugString(modifierAccessor.getDebugString());
             int arrIndex = Math.min(index, bitmapComparers.length - 1);
-            createTest().addCanvasClient(canvasClient).runWithComparer(bitmapComparers[arrIndex]);
+            createTest()
+                    .addCanvasClient(modifierAccessor.getDebugString(), canvasClient)
+                    .runWithComparer(bitmapComparers[arrIndex]);
             index++;
         } while (modifierAccessor.step());
     }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
index 3b1df30..c8ca8c3 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
@@ -2,6 +2,7 @@
 
 import android.graphics.Color;
 import android.graphics.Outline;
+import android.graphics.Path;
 import android.graphics.Rect;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
@@ -15,6 +16,8 @@
 import android.uirendering.cts.R;
 import org.junit.Test;
 
+import static org.junit.Assert.assertFalse;
+
 /**
  * This tests view clipping by modifying properties of blue_padded_layout, and validating
  * the resulting rect of content.
@@ -23,46 +26,35 @@
  */
 @MediumTest
 public class ViewClippingTests extends ActivityTestBase {
-    final Rect FULL_RECT = new Rect(0, 0, 90, 90);
-    final Rect BOUNDS_RECT = new Rect(0, 0, 80, 80);
-    final Rect PADDED_RECT = new Rect(15, 16, 63, 62);
-    final Rect OUTLINE_RECT = new Rect(1, 2, 78, 79);
-    final Rect CLIP_BOUNDS_RECT = new Rect(10, 20, 50, 60);
+    static final Rect FULL_RECT = new Rect(0, 0, 90, 90);
+    static final Rect BOUNDS_RECT = new Rect(0, 0, 80, 80);
+    static final Rect PADDED_RECT = new Rect(15, 16, 63, 62);
+    static final Rect OUTLINE_RECT = new Rect(1, 2, 78, 79);
+    static final Rect CLIP_BOUNDS_RECT = new Rect(10, 20, 50, 60);
 
-    final ViewInitializer BOUNDS_CLIP_INIT = new ViewInitializer() {
-        @Override
-        public void initializeView(View rootView) {
-            ((ViewGroup)rootView).setClipChildren(true);
-        }
+    static final ViewInitializer BOUNDS_CLIP_INIT =
+            rootView -> ((ViewGroup)rootView).setClipChildren(true);
+
+    static final ViewInitializer PADDING_CLIP_INIT = rootView -> {
+        ViewGroup child = (ViewGroup) rootView.findViewById(R.id.child);
+        child.setClipToPadding(true);
+        child.setWillNotDraw(true);
+        child.addView(new UnclippedBlueView(rootView.getContext()));
     };
-    final ViewInitializer PADDING_CLIP_INIT = new ViewInitializer() {
-        @Override
-        public void initializeView(View rootView) {
-            ViewGroup child = (ViewGroup) rootView.findViewById(R.id.child);
-            child.setClipToPadding(true);
-            child.setWillNotDraw(true);
-            child.addView(new UnclippedBlueView(rootView.getContext()));
-        }
+
+    static final ViewInitializer OUTLINE_CLIP_INIT = rootView -> {
+        View child = rootView.findViewById(R.id.child);
+        child.setOutlineProvider(new ViewOutlineProvider() {
+            @Override
+            public void getOutline(View view, Outline outline) {
+                outline.setRect(OUTLINE_RECT);
+            }
+        });
+        child.setClipToOutline(true);
     };
-    final ViewInitializer OUTLINE_CLIP_INIT = new ViewInitializer() {
-        @Override
-        public void initializeView(View rootView) {
-            View child = rootView.findViewById(R.id.child);
-            child.setOutlineProvider(new ViewOutlineProvider() {
-                @Override
-                public void getOutline(View view, Outline outline) {
-                    outline.setRect(OUTLINE_RECT);
-                }
-            });
-            child.setClipToOutline(true);
-        }
-    };
-    final ViewInitializer CLIP_BOUNDS_CLIP_INIT = new ViewInitializer() {
-        @Override
-        public void initializeView(View view) {
-            view.setClipBounds(CLIP_BOUNDS_RECT);
-        }
-    };
+
+    static final ViewInitializer CLIP_BOUNDS_CLIP_INIT =
+            view -> view.setClipBounds(CLIP_BOUNDS_RECT);
 
     static BitmapVerifier makeClipVerifier(Rect blueBoundsRect) {
         // very high error tolerance, since all these tests care about is clip alignment
@@ -96,6 +88,7 @@
                 .addLayout(R.layout.blue_padded_layout, PADDING_CLIP_INIT)
                 .runWithVerifier(makeClipVerifier(PADDED_RECT));
     }
+    // TODO: add tests with clip + scroll, and with interesting combinations of the above
 
     @Test
     public void testSimpleOutlineClip() {
@@ -110,5 +103,25 @@
                 .runWithVerifier(makeClipVerifier(FULL_RECT));
     }
 
-    // TODO: add tests with clip + scroll, and with interesting combinations of the above
+    @Test
+    public void testOvalOutlineClip() {
+        // In hw this works because clipping to a non-round rect isn't supported, and is no-op'd.
+        // In sw this works because Outline clipping isn't supported.
+        createTest()
+                .addLayout(R.layout.blue_padded_layout, view -> {
+                    view.setOutlineProvider(new ViewOutlineProvider() {
+                        Path mPath = new Path();
+                        @Override
+                        public void getOutline(View view, Outline outline) {
+                            mPath.reset();
+                            mPath.addOval(0, 0, view.getWidth(), view.getHeight(),
+                                    Path.Direction.CW);
+                            outline.setConvexPath(mPath);
+                            assertFalse(outline.canClip()); // NOTE: non-round-rect, so can't clip
+                        }
+                    });
+                    view.setClipToOutline(true); // should do nothing, since non-rect clip
+                })
+                .runWithVerifier(makeClipVerifier(FULL_RECT));
+    }
 }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
index f82bb40..e634528 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
@@ -145,7 +145,7 @@
     protected Bitmap captureRenderSpec(TestCase testCase) {
         Point testOffset = getActivity().enqueueRenderSpecAndWait(
                 testCase.layoutID, testCase.canvasClient,
-                testCase.webViewUrl, testCase.viewInitializer, testCase.useHardware);
+                null, testCase.viewInitializer, testCase.useHardware);
         testCase.wasTestRan = true;
         return takeScreenshot(testOffset);
     }
@@ -260,36 +260,33 @@
             });
         }
 
-        public TestCaseBuilder addWebView(String webViewUrl,
-                @Nullable ViewInitializer viewInitializer) {
-            return addWebView(webViewUrl, viewInitializer, false)
-                    .addWebView(webViewUrl, viewInitializer, true);
-        }
-
         public TestCaseBuilder addLayout(int layoutId, @Nullable ViewInitializer viewInitializer) {
             return addLayout(layoutId, viewInitializer, false)
                     .addLayout(layoutId, viewInitializer, true);
         }
 
-        public TestCaseBuilder addCanvasClient(CanvasClient canvasClient) {
-            return addCanvasClient(canvasClient, false)
-                    .addCanvasClient(canvasClient, true);
-        }
-
-        public TestCaseBuilder addWebView(String webViewUrl,
-                @Nullable ViewInitializer viewInitializer, boolean useHardware) {
-            mTestCases.add(new TestCase(null, 0, webViewUrl, viewInitializer, useHardware));
-            return this;
-        }
-
         public TestCaseBuilder addLayout(int layoutId, @Nullable ViewInitializer viewInitializer,
-                boolean useHardware) {
-            mTestCases.add(new TestCase(null, layoutId, null, viewInitializer, useHardware));
+                                         boolean useHardware) {
+            mTestCases.add(new TestCase(layoutId, viewInitializer, useHardware));
             return this;
         }
 
+        public TestCaseBuilder addCanvasClient(CanvasClient canvasClient) {
+            return addCanvasClient(null, canvasClient);
+        }
+
         public TestCaseBuilder addCanvasClient(CanvasClient canvasClient, boolean useHardware) {
-            mTestCases.add(new TestCase(canvasClient, 0, null, null, useHardware));
+            return addCanvasClient(null, canvasClient, useHardware);
+        }
+
+        public TestCaseBuilder addCanvasClient(String debugString, CanvasClient canvasClient) {
+            return addCanvasClient(debugString, canvasClient, false)
+                    .addCanvasClient(debugString, canvasClient, true);
+        }
+
+        public TestCaseBuilder addCanvasClient(String debugString,
+                    CanvasClient canvasClient, boolean useHardware) {
+            mTestCases.add(new TestCase(canvasClient, debugString, useHardware));
             return this;
         }
 
@@ -300,39 +297,35 @@
 
     private class TestCase {
         public int layoutID;
-        public CanvasClient canvasClient;
-        public String webViewUrl;
         public ViewInitializer viewInitializer;
-        public boolean useHardware;
-        public boolean wasTestRan;
 
-        public TestCase(CanvasClient client, int id, String viewUrl,
-                ViewInitializer viewInitializer, boolean useHardware) {
-            int count = 0;
-            count += (client == null ? 0 : 1);
-            count += (viewUrl == null ? 0 : 1);
-            count += (id == 0 ? 0 : 1);
-            assert(count == 1);
-            assert(client == null || viewInitializer == null);
-            this.layoutID = id;
-            this.canvasClient = client;
-            this.webViewUrl = viewUrl;
+        public CanvasClient canvasClient;
+        public String canvasClientDebugString;
+
+        public boolean useHardware;
+        public boolean wasTestRan = false;
+
+        public TestCase(int layoutId, ViewInitializer viewInitializer, boolean useHardware) {
+            this.layoutID = layoutId;
             this.viewInitializer = viewInitializer;
             this.useHardware = useHardware;
-            this.wasTestRan = false;
+        }
+
+        public TestCase(CanvasClient client, String debugString, boolean useHardware) {
+            this.canvasClient = client;
+            this.canvasClientDebugString = debugString;
+            this.useHardware = useHardware;
         }
 
         public String getDebugString() {
             String debug = "";
             if (canvasClient != null) {
                 debug += "CanvasClient : ";
-                if (canvasClient.getDebugString() != null) {
-                    debug += canvasClient.getDebugString();
+                if (canvasClientDebugString != null) {
+                    debug += canvasClientDebugString;
                 } else {
                     debug += "no debug string given";
                 }
-            } else if (webViewUrl != null) {
-                debug += "WebView URL : " + webViewUrl;
             } else {
                 debug += "Layout resource : " +
                         getActivity().getResources().getResourceName(layoutID);
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/CanvasClient.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/CanvasClient.java
index a99c576..99f6cc7 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/CanvasClient.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/CanvasClient.java
@@ -20,16 +20,6 @@
 /**
  * A class that the tester will implement and create a set of drawing calls the tests would use
  */
-public abstract class CanvasClient {
-    private String mDebugString;
-
-    public abstract void draw(Canvas canvas, int width, int height);
-
-    public String getDebugString() {
-        return mDebugString;
-    }
-
-    public void setDebugString(String debugString) {
-        mDebugString = debugString;
-    }
+public interface CanvasClient {
+    void draw(Canvas canvas, int width, int height);
 }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ViewInitializer.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ViewInitializer.java
index 9a3cbb1..43e1fa6 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ViewInitializer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ViewInitializer.java
@@ -20,6 +20,6 @@
 /**
  * Called after a view is created to set various properties on the view
  */
-public abstract class ViewInitializer {
-    public abstract void initializeView(View view);
+public interface ViewInitializer {
+    void initializeView(View view);
 }
diff --git a/tests/tests/view/src/android/view/cts/ContextThemeWrapperTest.java b/tests/tests/view/src/android/view/cts/ContextThemeWrapperTest.java
index b25f733..ccf37949 100644
--- a/tests/tests/view/src/android/view/cts/ContextThemeWrapperTest.java
+++ b/tests/tests/view/src/android/view/cts/ContextThemeWrapperTest.java
@@ -17,6 +17,7 @@
 package android.view.cts;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.Resources.Theme;
@@ -25,7 +26,6 @@
 
 import android.view.cts.R;
 
-
 public class ContextThemeWrapperTest extends AndroidTestCase {
     private static final int SYSTEM_DEFAULT_THEME = 0;
 
@@ -103,6 +103,22 @@
         }).test());
     }
 
+    public void testApplyOverrideConfiguration() {
+        Context context = getContext();
+        final int realDensity = context.getResources().getConfiguration().densityDpi;
+        final int expectedDensity = realDensity + 1;
+
+        ContextThemeWrapper contextThemeWrapper = new ContextThemeWrapper(
+                context, SYSTEM_DEFAULT_THEME);
+
+        Configuration overrideConfig = new Configuration();
+        overrideConfig.densityDpi = expectedDensity;
+        contextThemeWrapper.applyOverrideConfiguration(overrideConfig);
+
+        Configuration actualConfiguration = contextThemeWrapper.getResources().getConfiguration();
+        assertEquals(expectedDensity, actualConfiguration.densityDpi);
+    }
+
     private void assertEqualsTextAppearanceStyle(TypedArray ta) {
         final int defValue = -1;
         // get Theme and assert
diff --git a/tests/tests/view/src/android/view/cts/KeyboardShortcutGroupTest.java b/tests/tests/view/src/android/view/cts/KeyboardShortcutGroupTest.java
new file mode 100644
index 0000000..067f0bb
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/KeyboardShortcutGroupTest.java
@@ -0,0 +1,97 @@
+package android.view.cts;
+
+import android.os.Parcel;
+import android.test.InstrumentationTestCase;
+import android.view.KeyEvent;
+import android.view.KeyboardShortcutGroup;
+import android.view.KeyboardShortcutInfo;
+
+import com.google.android.collect.Lists;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for {@link android.view.KeyboardShortcutGroup}.
+ */
+public class KeyboardShortcutGroupTest extends InstrumentationTestCase {
+    private static final CharSequence TEST_LABEL = "Test Group Label";
+    private final List<KeyboardShortcutInfo> TEST_ITEMS = Lists.newArrayList(
+            new KeyboardShortcutInfo("Item 1", KeyEvent.KEYCODE_U, KeyEvent.META_CTRL_ON),
+            new KeyboardShortcutInfo("Item 2", KeyEvent.KEYCODE_F, KeyEvent.META_CTRL_ON));
+
+    public void testConstructor() {
+        KeyboardShortcutGroup group = new KeyboardShortcutGroup(TEST_LABEL, TEST_ITEMS);
+
+        assertEquals(TEST_LABEL, group.getLabel());
+        assertEquals(TEST_ITEMS, group.getItems());
+        assertFalse(group.isSystemGroup());
+        assertEquals(0, group.describeContents());
+    }
+
+    public void testShortConstructor() {
+        KeyboardShortcutGroup group = new KeyboardShortcutGroup(TEST_LABEL);
+
+        assertEquals(TEST_LABEL, group.getLabel());
+        assertNotNull(group.getItems());
+        assertFalse(group.isSystemGroup());
+        assertEquals(0, group.describeContents());
+    }
+
+    public void testSystemConstructor() {
+        KeyboardShortcutGroup group = new KeyboardShortcutGroup(TEST_LABEL, TEST_ITEMS, true);
+
+        assertEquals(TEST_LABEL, group.getLabel());
+        assertEquals(TEST_ITEMS, group.getItems());
+        assertTrue(group.isSystemGroup());
+        assertEquals(0, group.describeContents());
+    }
+
+    public void testSystemShortConstructor() {
+        KeyboardShortcutGroup group = new KeyboardShortcutGroup(TEST_LABEL, true);
+
+        assertEquals(TEST_LABEL, group.getLabel());
+        assertNotNull(group.getItems());
+        assertTrue(group.isSystemGroup());
+        assertEquals(0, group.describeContents());
+    }
+
+    public void testConstructorChecksList() {
+        try {
+            KeyboardShortcutGroup group = new KeyboardShortcutGroup(TEST_LABEL, null);
+        } catch (NullPointerException expected) {
+            return;
+        }
+        fail();
+    }
+
+    public void testAddItem() {
+        KeyboardShortcutGroup group = new KeyboardShortcutGroup(TEST_LABEL, TEST_ITEMS);
+
+        group.addItem(new KeyboardShortcutInfo(
+                "Additional item", KeyEvent.KEYCODE_P, KeyEvent.META_CTRL_ON));
+
+        final int newSize = group.getItems().size();
+        assertEquals(TEST_ITEMS.size() + 1, newSize);
+        assertEquals("Additional item", group.getItems().get(newSize - 1).getLabel());
+    }
+
+    public void testWriteToParcelAndRead() {
+        Parcel dest = Parcel.obtain();
+        KeyboardShortcutGroup group = new KeyboardShortcutGroup(TEST_LABEL, TEST_ITEMS, true);
+        group.writeToParcel(dest, 0);
+
+        dest.setDataPosition(0);
+        KeyboardShortcutGroup result = KeyboardShortcutGroup.CREATOR.createFromParcel(dest);
+
+        assertEquals(TEST_LABEL, result.getLabel());
+        assertEquals(TEST_ITEMS.size(), result.getItems().size());
+        assertEquals(TEST_ITEMS.get(0).getLabel(), result.getItems().get(0).getLabel());
+        assertEquals(TEST_ITEMS.get(1).getLabel(), result.getItems().get(1).getLabel());
+        assertEquals(TEST_ITEMS.get(0).getKeycode(), result.getItems().get(0).getKeycode());
+        assertEquals(TEST_ITEMS.get(1).getKeycode(), result.getItems().get(1).getKeycode());
+        assertEquals(TEST_ITEMS.get(0).getModifiers(), result.getItems().get(0).getModifiers());
+        assertEquals(TEST_ITEMS.get(1).getModifiers(), result.getItems().get(1).getModifiers());
+        assertTrue(result.isSystemGroup());
+    }
+}
diff --git a/tests/tests/widget/AndroidManifest.xml b/tests/tests/widget/AndroidManifest.xml
index 5acfc18..dcfe4c1 100644
--- a/tests/tests/widget/AndroidManifest.xml
+++ b/tests/tests/widget/AndroidManifest.xml
@@ -77,7 +77,15 @@
         </activity>
 
         <activity android:name="android.widget.cts.ImageViewCtsActivity"
-            android:label="ImageViewCtsActivity">
+                  android:label="ImageViewCtsActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.widget.cts.SwitchCtsActivity"
+                  android:label="SwitchCtsActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
@@ -352,6 +360,14 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.widget.cts.CalendarViewCtsActivity"
+                  android:label="CalendarViewCtsActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="android.app.ActivityGroup"
             android:label="ActivityGroup" />
 
diff --git a/tests/tests/widget/res/drawable/magenta_fill.xml b/tests/tests/widget/res/drawable/magenta_fill.xml
new file mode 100644
index 0000000..cbb594f
--- /dev/null
+++ b/tests/tests/widget/res/drawable/magenta_fill.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="#FF00FF" />
+</shape>
\ No newline at end of file
diff --git a/tests/tests/widget/res/drawable/yellow_fill.xml b/tests/tests/widget/res/drawable/yellow_fill.xml
new file mode 100644
index 0000000..3bd80977
--- /dev/null
+++ b/tests/tests/widget/res/drawable/yellow_fill.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="#FFFF00" />
+</shape>
\ No newline at end of file
diff --git a/tests/tests/widget/res/layout/calendarview_layout.xml b/tests/tests/widget/res/layout/calendarview_layout.xml
new file mode 100644
index 0000000..3bc5e47
--- /dev/null
+++ b/tests/tests/widget/res/layout/calendarview_layout.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fillViewport="true">
+
+    <LinearLayout
+        android:id="@+id/container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <CalendarView
+            android:id="@+id/calendar_view_material"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:firstDayOfWeek="2"
+            android:dateTextAppearance="@style/TextAppearance.WithColor"
+            android:weekDayTextAppearance="@style/TextAppearance.WithColorGreen" />
+
+        <!-- CalendarView in Holo Light style for testing attributes and APIs that control
+             the deprecated visual aspects of this widget. -->
+        <CalendarView
+            style="@android:style/Widget.Holo.Light.CalendarView"
+            android:id="@+id/calendar_view_holoyolo"
+            android:layout_width="match_parent"
+            android:layout_height="320dip"
+            android:firstDayOfWeek="3"
+            android:shownWeekCount="5"
+            android:showWeekNumber="false"
+            android:selectedWeekBackgroundColor="@color/calendarview_week_background"
+            android:focusedMonthDateColor="@color/calendarview_focusedmonthdate"
+            android:unfocusedMonthDateColor="@color/calendarview_unfocusedmonthdate"
+            android:dateTextAppearance="@style/TextAppearance.WithColor"
+            android:weekDayTextAppearance="@style/TextAppearance.WithColorGreen"
+            android:selectedDateVerticalBar="@drawable/blue_fill" />
+
+    </LinearLayout>
+
+</ScrollView>
diff --git a/tests/tests/widget/res/layout/popupwindow.xml b/tests/tests/widget/res/layout/popupwindow.xml
index d84770d..cf69831 100644
--- a/tests/tests/widget/res/layout/popupwindow.xml
+++ b/tests/tests/widget/res/layout/popupwindow.xml
@@ -20,40 +20,76 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <android.widget.cts.MockViewForListPopupWindow
+    <View
         android:id="@+id/anchor_upper_left"
         android:layout_width="10dp"
         android:layout_height="10dp"
-        android:layout_alignParentTop="true"
         android:layout_alignParentLeft="true"
-        android:background="#f0f" />
-
-    <View android:id="@+id/anchor_upper"
-        android:layout_width="10dp"
-        android:layout_height="30dp"
         android:layout_alignParentTop="true"
-        android:layout_centerHorizontal="true"
         android:background="#f00" />
 
-    <View android:id="@+id/anchor_lower"
+    <View
+        android:id="@+id/anchor_upper"
         android:layout_width="10dp"
-        android:layout_height="30dp"
-        android:layout_alignParentBottom="true"
+        android:layout_height="10dp"
         android:layout_centerHorizontal="true"
-        android:background="#0f0" />
+        android:layout_alignParentTop="true"
+        android:background="#f00" />
 
-    <View android:id="@+id/anchor_middle_left"
-        android:layout_width="30dp"
+    <View
+        android:id="@+id/anchor_upper_right"
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:layout_alignParentRight="true"
+        android:layout_alignParentTop="true"
+        android:background="#f00" />
+
+    <View
+        android:id="@+id/anchor_middle_left"
+        android:layout_width="10dp"
         android:layout_height="10dp"
         android:layout_alignParentLeft="true"
         android:layout_centerVertical="true"
-        android:background="#00f" />
+        android:background="#0f0" />
 
-    <View android:id="@+id/anchor_middle_right"
-        android:layout_width="30dp"
+    <View
+        android:id="@+id/anchor_middle"
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:layout_centerHorizontal="true"
+        android:layout_centerVertical="true"
+        android:background="#0f0" />
+
+    <View
+        android:id="@+id/anchor_middle_right"
+        android:layout_width="10dp"
         android:layout_height="10dp"
         android:layout_alignParentRight="true"
         android:layout_centerVertical="true"
-        android:background="#ff0" />
+        android:background="#0f0" />
+
+    <View
+        android:id="@+id/anchor_lower_left"
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentBottom="true"
+        android:background="#00f" />
+
+    <View
+        android:id="@+id/anchor_lower"
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:layout_centerHorizontal="true"
+        android:layout_alignParentBottom="true"
+        android:background="#00f" />
+
+    <View
+        android:id="@+id/anchor_lower_right"
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:layout_alignParentRight="true"
+        android:layout_alignParentBottom="true"
+        android:background="#00f" />
 
 </RelativeLayout>
diff --git a/tests/tests/widget/res/layout/switch_layout.xml b/tests/tests/widget/res/layout/switch_layout.xml
index a34845b..12e10d2 100644
--- a/tests/tests/widget/res/layout/switch_layout.xml
+++ b/tests/tests/widget/res/layout/switch_layout.xml
@@ -16,6 +16,7 @@
   -->
 
 <Switch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/switch_view"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:thumbTint="@android:color/white"
diff --git a/tests/tests/widget/res/values/colors.xml b/tests/tests/widget/res/values/colors.xml
index f3cc325..f104a6d2 100644
--- a/tests/tests/widget/res/values/colors.xml
+++ b/tests/tests/widget/res/values/colors.xml
@@ -23,4 +23,14 @@
     <color name="testcolor1">#ff00ff00</color>
     <color name="testcolor2">#ffff0000</color>
     <color name="failColor">#ff0000ff</color>
+
+    <color name="calendarview_week_background">#40FF0000</color>
+    <color name="calendarview_focusedmonthdate">#9080A0FF</color>
+    <color name="calendarview_unfocusedmonthdate">#9070F080</color>
+
+    <color name="calendarview_week_background_new">#60808000</color>
+    <color name="calendarview_focusedmonthdate_new">#A0B020FF</color>
+    <color name="calendarview_unfocusedmonthdate_new">#4070F0F0</color>
+    <color name="calendarview_week_number_new">#9090FF</color>
+    <color name="calendarview_week_separatorline_new">#AFAF00</color>
 </resources>
diff --git a/tests/tests/widget/res/values/styles.xml b/tests/tests/widget/res/values/styles.xml
index da22652..345b450 100644
--- a/tests/tests/widget/res/values/styles.xml
+++ b/tests/tests/widget/res/values/styles.xml
@@ -71,6 +71,18 @@
         <item name="android:textColor">#ffff0000</item>
     </style>
 
+    <style name="TextAppearance.WithColorGreen">
+        <item name="android:textColor">#ff00ff00</item>
+    </style>
+
+    <style name="TextAppearance.WithColorBlue">
+        <item name="android:textColor">#ff0000ff</item>
+    </style>
+
+    <style name="TextAppearance.WithColorMagenta">
+        <item name="android:textColor">#ffff00ff</item>
+    </style>
+
     <style name="TextAppearance.All">
         <item name="android:textColor">@drawable/black</item>
         <item name="android:textSize">20px</item>
@@ -188,4 +200,6 @@
         <item name="android:tabStripLeft">@drawable/icon_green</item>
         <item name="android:tabStripRight">@drawable/icon_red</item>
     </style>
+
+    <style name="ToolbarPopupTheme_Test" parent="@android:style/ThemeOverlay.Material.Light" />
 </resources>
diff --git a/tests/tests/widget/src/android/widget/cts/CalendarViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/CalendarViewCtsActivity.java
new file mode 100644
index 0000000..b0a15bf
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/CalendarViewCtsActivity.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.CalendarView;
+import android.widget.Toolbar;
+
+/**
+ * A minimal application for {@link CalendarView} test.
+ */
+public class CalendarViewCtsActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.calendarview_layout);
+    }
+}
+
diff --git a/tests/tests/widget/src/android/widget/cts/CalendarViewTest.java b/tests/tests/widget/src/android/widget/cts/CalendarViewTest.java
new file mode 100644
index 0000000..31ad341
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/CalendarViewTest.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget.cts;
+
+import android.annotation.ColorInt;
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.CalendarView;
+import android.widget.cts.util.TestUtils;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+@MediumTest
+public class CalendarViewTest extends ActivityInstrumentationTestCase2<CalendarViewCtsActivity> {
+    private CalendarViewCtsActivity mActivity;
+    private CalendarView mCalendarViewMaterial;
+    private CalendarView mCalendarViewHolo;
+
+    public CalendarViewTest() {
+        super("android.widget.cts", CalendarViewCtsActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+        mCalendarViewMaterial = (CalendarView) mActivity.findViewById(R.id.calendar_view_material);
+        mCalendarViewHolo = (CalendarView) mActivity.findViewById(R.id.calendar_view_holoyolo);
+
+        // Initialize both calendar views to the current date
+        final long currentDate = new GregorianCalendar().getTime().getTime();
+        getInstrumentation().runOnMainSync(() -> {
+            mCalendarViewMaterial.setDate(currentDate);
+            mCalendarViewHolo.setDate(currentDate);
+        });
+    }
+
+    public void testConstructor() {
+        new CalendarView(mActivity);
+
+        new CalendarView(mActivity, null);
+
+        new CalendarView(mActivity, null, android.R.attr.calendarViewStyle);
+
+        new CalendarView(mActivity, null, 0, android.R.style.Widget_Material_Light_CalendarView);
+    }
+
+    public void testAccessDate() {
+        final Instrumentation instrumentation = getInstrumentation();
+
+        // Go back one year
+        final Calendar newCalendar = new GregorianCalendar();
+        newCalendar.set(Calendar.YEAR, newCalendar.get(Calendar.YEAR) - 1);
+        final long yearAgoDate = newCalendar.getTime().getTime();
+
+        instrumentation.runOnMainSync(
+                () -> mCalendarViewMaterial.setDate(yearAgoDate));
+        assertEquals(yearAgoDate, mCalendarViewMaterial.getDate());
+
+        // Go forward two years (one year from current date in aggregate)
+        newCalendar.set(Calendar.YEAR, newCalendar.get(Calendar.YEAR) + 2);
+        final long yearHenceDate = newCalendar.getTime().getTime();
+
+        instrumentation.runOnMainSync(
+                () -> mCalendarViewMaterial.setDate(yearHenceDate, true, false));
+        assertEquals(yearHenceDate, mCalendarViewMaterial.getDate());
+    }
+
+    public void testAccessMinMaxDate() {
+        final Instrumentation instrumentation = getInstrumentation();
+
+        // Use a range of minus/plus one year as min/max dates
+        final Calendar minCalendar = new GregorianCalendar();
+        minCalendar.set(Calendar.YEAR, minCalendar.get(Calendar.YEAR) - 1);
+        final Calendar maxCalendar = new GregorianCalendar();
+        maxCalendar.set(Calendar.YEAR, maxCalendar.get(Calendar.YEAR) + 1);
+
+        final long minDate = minCalendar.getTime().getTime();
+        final long maxDate = maxCalendar.getTime().getTime();
+
+        instrumentation.runOnMainSync(() -> {
+            mCalendarViewMaterial.setMinDate(minDate);
+            mCalendarViewMaterial.setMaxDate(maxDate);
+        });
+
+        assertEquals(mCalendarViewMaterial.getMinDate(), minDate);
+        assertEquals(mCalendarViewMaterial.getMaxDate(), maxDate);
+    }
+
+    public void testAppearanceMaterial() {
+        // The logic in this method is performed on a Material-styled CalendarView and
+        // non-deprecated attributes / visual appearance APIs
+
+        // Test the initial appearance defined in the layout XML
+        assertEquals(2, mCalendarViewMaterial.getFirstDayOfWeek());
+        assertEquals(R.style.TextAppearance_WithColor,
+                mCalendarViewMaterial.getDateTextAppearance());
+        assertEquals(R.style.TextAppearance_WithColorGreen,
+                mCalendarViewMaterial.getWeekDayTextAppearance());
+
+        final Instrumentation instrumentation = getInstrumentation();
+
+        // Change the visual appearance of the widget
+        instrumentation.runOnMainSync(() -> {
+            mCalendarViewMaterial.setFirstDayOfWeek(3);
+            mCalendarViewMaterial.setDateTextAppearance(R.style.TextAppearance_WithColorBlue);
+            mCalendarViewMaterial.setWeekDayTextAppearance(R.style.TextAppearance_WithColorMagenta);
+        });
+
+        assertEquals(3, mCalendarViewMaterial.getFirstDayOfWeek());
+        assertEquals(R.style.TextAppearance_WithColorBlue,
+                mCalendarViewMaterial.getDateTextAppearance());
+        assertEquals(R.style.TextAppearance_WithColorMagenta,
+                mCalendarViewMaterial.getWeekDayTextAppearance());
+    }
+
+    public void testAppearanceHolo() {
+        // All the logic in this method is performed on a Holo-styled CalendarView, as
+        // under Material design we are ignoring most of these decorative attributes
+
+        // Test the initial appearance defined in the layout XML
+        assertEquals(3, mCalendarViewHolo.getFirstDayOfWeek());
+        assertEquals(5, mCalendarViewHolo.getShownWeekCount());
+        assertFalse(mCalendarViewHolo.getShowWeekNumber());
+        assertEquals(R.style.TextAppearance_WithColor,
+                mCalendarViewHolo.getDateTextAppearance());
+        assertEquals(R.style.TextAppearance_WithColorGreen,
+                mCalendarViewHolo.getWeekDayTextAppearance());
+        assertEquals(mActivity.getColor(R.color.calendarview_week_background),
+                mCalendarViewHolo.getSelectedWeekBackgroundColor());
+        assertEquals(mActivity.getColor(R.color.calendarview_focusedmonthdate),
+                mCalendarViewHolo.getFocusedMonthDateColor());
+        assertEquals(mActivity.getColor(R.color.calendarview_unfocusedmonthdate),
+                mCalendarViewHolo.getUnfocusedMonthDateColor());
+        TestUtils.assertAllPixelsOfColor("Selected date vertical bar blue",
+                mCalendarViewHolo.getSelectedDateVerticalBar(), 40, 40, true, 0xFF0000FF, 1, true);
+
+        final Instrumentation instrumentation = getInstrumentation();
+
+        // Change the visual appearance of the widget
+        final @ColorInt int newSelectedWeekBackgroundColor =
+                mActivity.getColor(R.color.calendarview_week_background_new);
+        final @ColorInt int newFocusedMonthDateColor =
+                mActivity.getColor(R.color.calendarview_focusedmonthdate_new);
+        final @ColorInt int newUnfocusedMonthDataColor =
+                mActivity.getColor(R.color.calendarview_unfocusedmonthdate_new);
+        final @ColorInt int newWeekNumberColor =
+                mActivity.getColor(R.color.calendarview_week_number_new);
+        final @ColorInt int newWeekSeparatorLineColor =
+                mActivity.getColor(R.color.calendarview_week_separatorline_new);
+
+        instrumentation.runOnMainSync(() -> {
+            mCalendarViewHolo.setFirstDayOfWeek(1);
+            mCalendarViewHolo.setShownWeekCount(4);
+            mCalendarViewHolo.setShowWeekNumber(true);
+            mCalendarViewHolo.setDateTextAppearance(R.style.TextAppearance_WithColorBlue);
+            mCalendarViewHolo.setWeekDayTextAppearance(R.style.TextAppearance_WithColorMagenta);
+            mCalendarViewHolo.setSelectedWeekBackgroundColor(newSelectedWeekBackgroundColor);
+            mCalendarViewHolo.setFocusedMonthDateColor(newFocusedMonthDateColor);
+            mCalendarViewHolo.setUnfocusedMonthDateColor(newUnfocusedMonthDataColor);
+            mCalendarViewHolo.setWeekNumberColor(newWeekNumberColor);
+            mCalendarViewHolo.setWeekSeparatorLineColor(newWeekSeparatorLineColor);
+        });
+
+        assertEquals(1, mCalendarViewHolo.getFirstDayOfWeek());
+        assertEquals(4, mCalendarViewHolo.getShownWeekCount());
+        assertTrue(mCalendarViewHolo.getShowWeekNumber());
+        assertEquals(R.style.TextAppearance_WithColorBlue,
+                mCalendarViewHolo.getDateTextAppearance());
+        assertEquals(R.style.TextAppearance_WithColorMagenta,
+                mCalendarViewHolo.getWeekDayTextAppearance());
+        assertEquals(newSelectedWeekBackgroundColor,
+                mCalendarViewHolo.getSelectedWeekBackgroundColor());
+        assertEquals(newFocusedMonthDateColor,
+                mCalendarViewHolo.getFocusedMonthDateColor());
+        assertEquals(newUnfocusedMonthDataColor,
+                mCalendarViewHolo.getUnfocusedMonthDateColor());
+        assertEquals(newWeekNumberColor,
+                mCalendarViewHolo.getWeekNumberColor());
+        assertEquals(newWeekSeparatorLineColor,
+                mCalendarViewHolo.getWeekSeparatorLineColor());
+
+        instrumentation.runOnMainSync(
+                () -> mCalendarViewHolo.setSelectedDateVerticalBar(R.drawable.yellow_fill));
+        TestUtils.assertAllPixelsOfColor("Selected date vertical bar yellow",
+                mCalendarViewHolo.getSelectedDateVerticalBar(), 40, 40, true, 0xFFFFFF00, 1, true);
+
+        instrumentation.runOnMainSync(
+                () -> mCalendarViewHolo.setSelectedDateVerticalBar(
+                        mActivity.getDrawable(R.drawable.magenta_fill)));
+        TestUtils.assertAllPixelsOfColor("Selected date vertical bar magenta",
+                mCalendarViewHolo.getSelectedDateVerticalBar(), 40, 40, true, 0xFFFF00FF, 1, true);
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
index 3054bab..cb7f2d6 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
@@ -19,7 +19,6 @@
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.os.SystemClock;
-import android.support.test.InstrumentationRegistry;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.view.Gravity;
@@ -29,6 +28,7 @@
 import android.view.MotionEvent;
 import android.view.SubMenu;
 import android.view.View;
+import android.widget.EditText;
 import android.widget.PopupMenu;
 
 import static org.mockito.Mockito.*;
@@ -51,6 +51,19 @@
         super.setUp();
         mInstrumentation = getInstrumentation();
         mActivity = getActivity();
+
+        try {
+            runTestOnUiThread(() -> {
+                // Disable and remove focusability on the first child of our activity so that
+                // it doesn't bring in the soft keyboard that can mess up with some of the tests
+                // (such as menu dismissal when we emulate a tap outside the menu bounds).
+                final EditText editText = (EditText) mActivity.findViewById(R.id.anchor_upper_left);
+                editText.setEnabled(false);
+                editText.setFocusable(false);
+            });
+        } catch (Throwable t) {
+            throw new RuntimeException(t);
+        }
     }
 
     @Override
diff --git a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
index 658307a..15a79bf 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
@@ -16,12 +16,16 @@
 
 package android.widget.cts;
 
+import junit.framework.AssertionFailedError;
+
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
 import android.graphics.Color;
+import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.Debug;
 import android.os.SystemClock;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
@@ -296,33 +300,281 @@
         assertEquals(width, mPopupWindow.getWidth());
     }
 
+    private static final int TOP = 0x00;
+    private static final int BOTTOM = 0x01;
+
+    private static final int LEFT = 0x00;
+    private static final int RIGHT = 0x01;
+
+    private static final int GREATER_THAN = 1;
+    private static final int LESS_THAN = -1;
+    private static final int EQUAL_TO = 0;
+
     public void testShowAsDropDown() {
-        int[] anchorXY = new int[2];
-        int[] viewOnScreenXY = new int[2];
-        int[] viewInWindowXY = new int[2];
+        final PopupWindow popup = createPopupWindow(createPopupContent(50, 50));
+        popup.setClipToScreenEnabled(false);
+        popup.setOverlapAnchor(false);
+        popup.setAnimationStyle(0);
+        popup.setExitTransition(null);
+        popup.setEnterTransition(null);
 
-        mPopupWindow = createPopupWindow(createPopupContent());
-        final View upperAnchor = mActivity.findViewById(R.id.anchor_upper);
+        assertPosition(popup, R.id.anchor_upper_left,
+                LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
+        assertPosition(popup, R.id.anchor_upper,
+                LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
+        assertPosition(popup, R.id.anchor_upper_right,
+                RIGHT, EQUAL_TO, RIGHT, TOP, EQUAL_TO, BOTTOM);
 
-        mInstrumentation.runOnMainSync(() -> mPopupWindow.showAsDropDown(upperAnchor));
-        mInstrumentation.waitForIdleSync();
+        assertPosition(popup, R.id.anchor_middle_left,
+                LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
+        assertPosition(popup, R.id.anchor_middle,
+                LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
+        assertPosition(popup, R.id.anchor_middle_right,
+                RIGHT, EQUAL_TO, RIGHT, TOP, EQUAL_TO, BOTTOM);
 
-        assertTrue(mPopupWindow.isShowing());
+        assertPosition(popup, R.id.anchor_lower_left,
+                LEFT, EQUAL_TO, LEFT, BOTTOM, EQUAL_TO, TOP);
+        assertPosition(popup, R.id.anchor_lower,
+                LEFT, EQUAL_TO, LEFT, BOTTOM, EQUAL_TO, TOP);
+        assertPosition(popup, R.id.anchor_lower_right,
+                RIGHT, EQUAL_TO, RIGHT, BOTTOM, EQUAL_TO, TOP);
+    }
 
-        mPopupWindow.getContentView().getLocationOnScreen(viewOnScreenXY);
-        upperAnchor.getLocationOnScreen(anchorXY);
-        mPopupWindow.getContentView().getLocationInWindow(viewInWindowXY);
-        assertEquals(anchorXY[0] + viewInWindowXY[0], viewOnScreenXY[0]);
-        assertEquals(anchorXY[1] + viewInWindowXY[1] + upperAnchor.getHeight(), viewOnScreenXY[1]);
+    public void testShowAsDropDown_ClipToScreen() {
+        final PopupWindow popup = createPopupWindow(createPopupContent(50, 50));
+        popup.setClipToScreenEnabled(true);
+        popup.setOverlapAnchor(false);
+        popup.setAnimationStyle(0);
+        popup.setExitTransition(null);
+        popup.setEnterTransition(null);
 
-        dismissPopup();
+        assertPosition(popup, R.id.anchor_upper_left,
+                LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
+        assertPosition(popup, R.id.anchor_upper,
+                LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
+        assertPosition(popup, R.id.anchor_upper_right,
+                RIGHT, EQUAL_TO, RIGHT, TOP, EQUAL_TO, BOTTOM);
+
+        assertPosition(popup, R.id.anchor_middle_left,
+                LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
+        assertPosition(popup, R.id.anchor_middle,
+                LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, BOTTOM);
+        assertPosition(popup, R.id.anchor_middle_right,
+                RIGHT, EQUAL_TO, RIGHT, TOP, EQUAL_TO, BOTTOM);
+
+        assertPosition(popup, R.id.anchor_lower_left,
+                LEFT, EQUAL_TO, LEFT, BOTTOM, EQUAL_TO, TOP);
+        assertPosition(popup, R.id.anchor_lower,
+                LEFT, EQUAL_TO, LEFT, BOTTOM, EQUAL_TO, TOP);
+        assertPosition(popup, R.id.anchor_lower_right,
+                RIGHT, EQUAL_TO, RIGHT, BOTTOM, EQUAL_TO, TOP);
+    }
+
+    public void testShowAsDropDown_ClipToScreen_Overlap() {
+        final PopupWindow popup = createPopupWindow(createPopupContent(50, 50));
+        popup.setClipToScreenEnabled(true);
+        popup.setOverlapAnchor(true);
+        popup.setAnimationStyle(0);
+        popup.setExitTransition(null);
+        popup.setEnterTransition(null);
+
+        assertPosition(popup, R.id.anchor_upper_left,
+                LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, TOP);
+        assertPosition(popup, R.id.anchor_upper,
+                LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, TOP);
+        assertPosition(popup, R.id.anchor_upper_right,
+                RIGHT, EQUAL_TO, RIGHT, TOP, EQUAL_TO, TOP);
+
+        assertPosition(popup, R.id.anchor_middle_left,
+                LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, TOP);
+        assertPosition(popup, R.id.anchor_middle,
+                LEFT, EQUAL_TO, LEFT, TOP, EQUAL_TO, TOP);
+        assertPosition(popup, R.id.anchor_middle_right,
+                RIGHT, EQUAL_TO, RIGHT, TOP, EQUAL_TO, TOP);
+
+        assertPosition(popup, R.id.anchor_lower_left,
+                LEFT, EQUAL_TO, LEFT, BOTTOM, EQUAL_TO, TOP);
+        assertPosition(popup, R.id.anchor_lower,
+                LEFT, EQUAL_TO, LEFT, BOTTOM, EQUAL_TO, TOP);
+        assertPosition(popup, R.id.anchor_lower_right,
+                RIGHT, EQUAL_TO, RIGHT, BOTTOM, EQUAL_TO, TOP);
+    }
+
+    public void testShowAsDropDown_ClipToScreen_Overlap_Offset() {
+        final PopupWindow popup = createPopupWindow(createPopupContent(50, 50));
+        popup.setClipToScreenEnabled(true);
+        popup.setOverlapAnchor(true);
+        popup.setAnimationStyle(0);
+        popup.setExitTransition(null);
+        popup.setEnterTransition(null);
+
+        final int offsetX = mActivity.findViewById(R.id.anchor_upper).getWidth() / 2;
+        final int offsetY = mActivity.findViewById(R.id.anchor_upper).getHeight() / 2;
+        final int gravity = Gravity.TOP | Gravity.START;
+
+        assertPosition(popup, R.id.anchor_upper_left,
+                LEFT, GREATER_THAN, LEFT, TOP, GREATER_THAN, TOP,
+                offsetX, offsetY, gravity);
+        assertPosition(popup, R.id.anchor_upper,
+                LEFT, GREATER_THAN, LEFT, TOP, GREATER_THAN, TOP,
+                offsetX, offsetY, gravity);
+        assertPosition(popup, R.id.anchor_upper_right,
+                RIGHT, EQUAL_TO, RIGHT, TOP, GREATER_THAN, TOP,
+                offsetX, offsetY, gravity);
+
+        assertPosition(popup, R.id.anchor_middle_left,
+                LEFT, GREATER_THAN, LEFT, TOP, GREATER_THAN, TOP,
+                offsetX, offsetY, gravity);
+        assertPosition(popup, R.id.anchor_middle,
+                LEFT, GREATER_THAN, LEFT, TOP, GREATER_THAN, TOP,
+                offsetX, offsetY, gravity);
+        assertPosition(popup, R.id.anchor_middle_right,
+                RIGHT, EQUAL_TO, RIGHT, TOP, GREATER_THAN, TOP,
+                offsetX, offsetY, gravity);
+
+        assertPosition(popup, R.id.anchor_lower_left,
+                LEFT, GREATER_THAN, LEFT, BOTTOM, LESS_THAN, BOTTOM,
+                offsetX, offsetY, gravity);
+        assertPosition(popup, R.id.anchor_lower,
+                LEFT, GREATER_THAN, LEFT, BOTTOM, LESS_THAN, BOTTOM,
+                offsetX, offsetY, gravity);
+        assertPosition(popup, R.id.anchor_lower_right,
+                RIGHT, EQUAL_TO, RIGHT, BOTTOM, LESS_THAN, BOTTOM,
+                offsetX, offsetY, gravity);
+    }
+
+    public void testShowAsDropDown_ClipToScreen_TooBig() {
+        final View rootView = mActivity.findViewById(R.id.anchor_upper_left).getRootView();
+        final int width = rootView.getWidth() * 2;
+        final int height = rootView.getHeight() * 2;
+
+        final PopupWindow popup = createPopupWindow(createPopupContent(width, height));
+        popup.setWidth(width);
+        popup.setHeight(height);
+
+        popup.setClipToScreenEnabled(true);
+        popup.setOverlapAnchor(false);
+        popup.setAnimationStyle(0);
+        popup.setExitTransition(null);
+        popup.setEnterTransition(null);
+
+        assertPosition(popup, R.id.anchor_upper_left,
+                LEFT, EQUAL_TO, LEFT, TOP, LESS_THAN, TOP);
+        assertPosition(popup, R.id.anchor_upper,
+                LEFT, LESS_THAN, LEFT, TOP, LESS_THAN, TOP);
+        assertPosition(popup, R.id.anchor_upper_right,
+                RIGHT, EQUAL_TO, RIGHT, TOP, LESS_THAN, TOP);
+
+        assertPosition(popup, R.id.anchor_middle_left,
+                LEFT, EQUAL_TO, LEFT, TOP, LESS_THAN, TOP);
+        assertPosition(popup, R.id.anchor_middle,
+                LEFT, LESS_THAN, LEFT, TOP, LESS_THAN, TOP);
+        assertPosition(popup, R.id.anchor_middle_right,
+                RIGHT, EQUAL_TO, RIGHT, TOP, LESS_THAN, TOP);
+
+        assertPosition(popup, R.id.anchor_lower_left,
+                LEFT, EQUAL_TO, LEFT, BOTTOM, EQUAL_TO, BOTTOM);
+        assertPosition(popup, R.id.anchor_lower,
+                LEFT, LESS_THAN, LEFT, BOTTOM, EQUAL_TO, BOTTOM);
+        assertPosition(popup, R.id.anchor_lower_right,
+                RIGHT, EQUAL_TO, RIGHT, BOTTOM, EQUAL_TO, BOTTOM);
+    }
+
+    private void assertPosition(PopupWindow popup, int anchorId,
+            int contentEdgeX, int operatorX, int anchorEdgeX,
+            int contentEdgeY, int operatorY, int anchorEdgeY) {
+        assertPosition(popup, anchorId,
+                contentEdgeX, operatorX, anchorEdgeX,
+                contentEdgeY, operatorY, anchorEdgeY,
+                0, 0, Gravity.TOP | Gravity.START);
+    }
+
+    private void assertPosition(PopupWindow popup, int anchorId,
+            int contentEdgeX, int operatorX, int anchorEdgeX,
+            int contentEdgeY, int operatorY, int anchorEdgeY,
+            int offsetX, int offsetY, int gravity) {
+        final View content = popup.getContentView();
+        final View anchor = mActivity.findViewById(anchorId);
+
+        getInstrumentation().runOnMainSync(() -> popup.showAsDropDown(
+                anchor, offsetX, offsetY, gravity));
+        getInstrumentation().waitForIdleSync();
+
+        assertTrue(popup.isShowing());
+        assertPositionX(content, contentEdgeX, operatorX, anchor, anchorEdgeX);
+        assertPositionY(content, contentEdgeY, operatorY, anchor, anchorEdgeY);
+
+        // Make sure it fits in the display frame.
+        final Rect displayFrame = new Rect();
+        anchor.getWindowVisibleDisplayFrame(displayFrame);
+        final Rect contentFrame = new Rect();
+        content.getBoundsOnScreen(contentFrame);
+        assertTrue("Content (" + contentFrame + ") extends outside display (" + displayFrame + ")",
+                displayFrame.contains(contentFrame));
+
+        getInstrumentation().runOnMainSync(() -> popup.dismiss());
+        getInstrumentation().waitForIdleSync();
+
+        assertFalse(popup.isShowing());
+    }
+
+    public static void assertPositionY(View content, int contentEdge, int flags,
+            View anchor, int anchorEdge) {
+        final int[] anchorOnScreenXY = new int[2];
+        anchor.getLocationOnScreen(anchorOnScreenXY);
+        int anchorY = anchorOnScreenXY[1];
+        if ((anchorEdge & BOTTOM) == BOTTOM) {
+            anchorY += anchor.getHeight();
+        }
+
+        final int[] contentOnScreenXY = new int[2];
+        content.getLocationOnScreen(contentOnScreenXY);
+        int contentY = contentOnScreenXY[1];
+        if ((contentEdge & BOTTOM) == BOTTOM) {
+            contentY += content.getHeight();
+        }
+
+        assertComparison(contentY, flags, anchorY);
+    }
+
+    private static void assertPositionX(View content, int contentEdge, int flags,
+            View anchor, int anchorEdge) {
+        final int[] anchorOnScreenXY = new int[2];
+        anchor.getLocationOnScreen(anchorOnScreenXY);
+        int anchorX = anchorOnScreenXY[0];
+        if ((anchorEdge & RIGHT) == RIGHT) {
+            anchorX += anchor.getWidth();
+        }
+
+        final int[] contentOnScreenXY = new int[2];
+        content.getLocationOnScreen(contentOnScreenXY);
+        int contentX = contentOnScreenXY[0];
+        if ((contentEdge & RIGHT) == RIGHT) {
+            contentX += content.getWidth();
+        }
+
+        assertComparison(contentX, flags, anchorX);
+    }
+
+    private static void assertComparison(int left, int operator, int right) {
+        switch (operator) {
+            case GREATER_THAN:
+                assertTrue(left + " <= " + right, left > right);
+                break;
+            case LESS_THAN:
+                assertTrue(left + " >= " + right, left < right);
+                break;
+            case EQUAL_TO:
+                assertTrue(left + " != " + right, left == right);
+                break;
+        }
     }
 
     public void testShowAtLocation() {
         int[] popupContentViewInWindowXY = new int[2];
         int[] popupContentViewOnScreenXY = new int[2];
 
-        mPopupWindow = createPopupWindow(createPopupContent());
+        mPopupWindow = createPopupWindow(createPopupContent(50, 50));
         // Do not attach within the decor; we will be measuring location
         // with regard to screen coordinates.
         mPopupWindow.setAttachedInDecor(false);
@@ -355,7 +607,7 @@
         int[] viewOnScreenXY = new int[2];
         int[] viewInWindowXY = new int[2];
 
-        mPopupWindow = createPopupWindow(createPopupContent());
+        mPopupWindow = createPopupWindow(createPopupContent(50, 50));
         final View upperAnchor = mActivity.findViewById(R.id.anchor_upper);
         upperAnchor.getLocationOnScreen(anchorXY);
         int height = upperAnchor.getHeight();
@@ -379,7 +631,7 @@
         int[] viewOnScreenXY = new int[2];
         int[] viewInWindowXY = new int[2];
 
-        mPopupWindow = createPopupWindow(createPopupContent());
+        mPopupWindow = createPopupWindow(createPopupContent(50, 50));
         final View upperAnchor = mActivity.findViewById(R.id.anchor_upper);
         upperAnchor.getLocationOnScreen(anchorXY);
 
@@ -397,7 +649,7 @@
     }
 
     public void testAccessWindowLayoutType() {
-        mPopupWindow = createPopupWindow(createPopupContent());
+        mPopupWindow = createPopupWindow(createPopupContent(50, 50));
         assertEquals(WindowManager.LayoutParams.TYPE_APPLICATION_PANEL,
                 mPopupWindow.getWindowLayoutType());
         mPopupWindow.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
@@ -406,7 +658,7 @@
     }
 
     public void testGetMaxAvailableHeight() {
-        mPopupWindow = createPopupWindow(createPopupContent());
+        mPopupWindow = createPopupWindow(createPopupContent(50, 50));
 
         View anchorView = mActivity.findViewById(R.id.anchor_upper);
         int avaliable = getDisplay().getHeight() - anchorView.getHeight();
@@ -447,7 +699,7 @@
 
     @UiThreadTest
     public void testDismiss() {
-        mPopupWindow = createPopupWindow(createPopupContent());
+        mPopupWindow = createPopupWindow(createPopupContent(50, 50));
         assertFalse(mPopupWindow.isShowing());
         View anchorView = mActivity.findViewById(R.id.anchor_upper);
         mPopupWindow.showAsDropDown(anchorView);
@@ -480,7 +732,7 @@
     }
 
     public void testUpdate() {
-        mPopupWindow = createPopupWindow(createPopupContent());
+        mPopupWindow = createPopupWindow(createPopupContent(50, 50));
         mPopupWindow.setBackgroundDrawable(null);
         showPopup();
 
@@ -529,7 +781,7 @@
 
         OnDismissListener dismissListener = mock(OnDismissListener.class);
 
-        mPopupWindow = createPopupWindow(createPopupContent());
+        mPopupWindow = createPopupWindow(createPopupContent(50, 50));
         mPopupWindow.setEnterTransition(enterTransition);
         mPopupWindow.setExitTransition(exitTransition);
         mPopupWindow.setOnDismissListener(dismissListener);
@@ -557,7 +809,7 @@
         int[] viewInWindowXY = new int[2];
 
         mInstrumentation.runOnMainSync(() -> {
-            mPopupWindow = createPopupWindow(createPopupContent());
+            mPopupWindow = createPopupWindow(createPopupContent(50, 50));
             // Do not attach within the decor; we will be measuring location
             // with regard to screen coordinates.
             mPopupWindow.setAttachedInDecor(false);
@@ -601,7 +853,7 @@
 
     public void testUpdateDimensionAndAlignAnchorView() {
         mInstrumentation.runOnMainSync(
-                () -> mPopupWindow = createPopupWindow(createPopupContent()));
+                () -> mPopupWindow = createPopupWindow(createPopupContent(50, 50)));
         mInstrumentation.waitForIdleSync();
 
         final View anchorView = mActivity.findViewById(R.id.anchor_upper);
@@ -636,7 +888,7 @@
         int[] viewInWindowOff = new int[2];
         int[] viewXY = new int[2];
 
-        mPopupWindow = createPopupWindow(createPopupContent());
+        mPopupWindow = createPopupWindow(createPopupContent(50, 50));
         final View anchorView = mActivity.findViewById(R.id.anchor_upper);
         // Do not update if it is not shown
         assertFalse(mPopupWindow.isShowing());
@@ -737,7 +989,8 @@
     }
 
     public void testIsAboveAnchor() {
-        mInstrumentation.runOnMainSync(() -> mPopupWindow = createPopupWindow(createPopupContent()));
+        mInstrumentation.runOnMainSync(() -> mPopupWindow = createPopupWindow(createPopupContent(50,
+                50)));
         mInstrumentation.waitForIdleSync();
         final View upperAnchor = mActivity.findViewById(R.id.anchor_upper);
 
@@ -746,7 +999,7 @@
         assertFalse(mPopupWindow.isAboveAnchor());
         dismissPopup();
 
-        mPopupWindow = createPopupWindow(createPopupContent());
+        mPopupWindow = createPopupWindow(createPopupContent(50, 50));
         final View lowerAnchor = mActivity.findViewById(R.id.anchor_lower);
 
         mInstrumentation.runOnMainSync(() -> mPopupWindow.showAsDropDown(lowerAnchor, 0, 0));
@@ -819,9 +1072,9 @@
         public void captureEndValues(TransitionValues transitionValues) {}
     }
 
-    private View createPopupContent() {
-        View popupView = new View(mActivity);
-        popupView.setLayoutParams(new ViewGroup.LayoutParams(50, 50));
+    private View createPopupContent(int width, int height) {
+        final View popupView = new View(mActivity);
+        popupView.setLayoutParams(new ViewGroup.LayoutParams(width, height));
         popupView.setBackgroundColor(Color.MAGENTA);
 
         return popupView;
@@ -831,6 +1084,7 @@
         PopupWindow window = new PopupWindow(mActivity);
         window.setWidth(100);
         window.setHeight(100);
+        window.setBackgroundDrawable(new ColorDrawable(Color.YELLOW));
         return window;
     }
 
diff --git a/tests/tests/widget/src/android/widget/cts/SwitchCtsActivity.java b/tests/tests/widget/src/android/widget/cts/SwitchCtsActivity.java
new file mode 100644
index 0000000..7be5831
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/SwitchCtsActivity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.Switch;
+import android.widget.cts.R;
+
+/**
+ * A minimal application for {@link Switch} test.
+ */
+public class SwitchCtsActivity extends Activity {
+    /**
+     * Called with the activity is first created.
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.switch_layout);
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/SwitchTest.java b/tests/tests/widget/src/android/widget/cts/SwitchTest.java
index e1124f3..216b17b 100644
--- a/tests/tests/widget/src/android/widget/cts/SwitchTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SwitchTest.java
@@ -16,65 +16,71 @@
 
 package android.widget.cts;
 
-import android.widget.cts.R;
-
-import android.content.Context;
+import android.app.Activity;
 import android.content.res.ColorStateList;
-import android.content.res.XmlResourceParser;
-import android.cts.util.WidgetTestUtils;
 import android.graphics.Color;
 import android.graphics.PorterDuff.Mode;
-import android.test.AndroidTestCase;
-import android.util.Xml;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.widget.Switch;
+import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
-import org.xmlpull.v1.XmlPullParserException;
 
 /**
  * Test {@link Switch}.
  */
-public class SwitchTest extends AndroidTestCase {
-    public void testConstructor() throws XmlPullParserException, IOException {
-        new Switch(mContext);
+@SmallTest
+public class SwitchTest extends ActivityInstrumentationTestCase<SwitchCtsActivity> {
+    private Activity mActivity;
+    private Switch mSwitch;
 
-        XmlResourceParser parser = mContext.getResources().getLayout(R.layout.switch_layout);
-        WidgetTestUtils.beginDocument(parser, "Switch");
-
-        new Switch(mContext, parser);
-
-        new Switch(mContext, parser, 0);
-
-        new Switch(mContext, parser, 0, 0);
+    public SwitchTest() {
+        super("android.widget.cts", SwitchCtsActivity.class);
     }
 
-    public void testAccessThumbTint() throws XmlPullParserException, IOException {
-        XmlResourceParser parser = mContext.getResources().getLayout(R.layout.switch_layout);
-        WidgetTestUtils.beginDocument(parser, "Switch");
-        Switch aSwitch = new Switch(mContext, parser);
-        assertEquals(Color.WHITE, aSwitch.getThumbTintList().getDefaultColor());
-        assertEquals(Mode.SRC_OVER, aSwitch.getThumbTintMode());
-
-        ColorStateList colors = ColorStateList.valueOf(Color.RED);
-        aSwitch.setThumbTintList(colors);
-        aSwitch.setThumbTintMode(Mode.XOR);
-
-        assertSame(colors, aSwitch.getThumbTintList());
-        assertEquals(Mode.XOR, aSwitch.getThumbTintMode());
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+        mSwitch = (Switch) mActivity.findViewById(R.id.switch_view);
     }
 
-    public void testAccessTrackTint() throws XmlPullParserException, IOException {
-        XmlResourceParser parser = mContext.getResources().getLayout(R.layout.switch_layout);
-        WidgetTestUtils.beginDocument(parser, "Switch");
-        Switch aSwitch = new Switch(mContext, parser);
-        assertEquals(Color.BLACK, aSwitch.getTrackTintList().getDefaultColor());
-        assertEquals(Mode.SRC_ATOP, aSwitch.getTrackTintMode());
+    @UiThreadTest
+    public void testConstructor() {
+        new Switch(mActivity);
+
+        new Switch(mActivity, null);
+
+        new Switch(mActivity, null, android.R.attr.switchStyle);
+
+        new Switch(mActivity, null, 0, android.R.style.Widget_Material_Light_CompoundButton_Switch);
+    }
+
+    @UiThreadTest
+    public void testAccessThumbTint() {
+        assertEquals(Color.WHITE, mSwitch.getThumbTintList().getDefaultColor());
+        assertEquals(Mode.SRC_OVER, mSwitch.getThumbTintMode());
 
         ColorStateList colors = ColorStateList.valueOf(Color.RED);
-        aSwitch.setTrackTintList(colors);
-        aSwitch.setTrackTintMode(Mode.XOR);
+        mSwitch.setThumbTintList(colors);
+        mSwitch.setThumbTintMode(Mode.XOR);
 
-        assertSame(colors, aSwitch.getTrackTintList());
-        assertEquals(Mode.XOR, aSwitch.getTrackTintMode());
+        assertSame(colors, mSwitch.getThumbTintList());
+        assertEquals(Mode.XOR, mSwitch.getThumbTintMode());
+    }
+
+    @UiThreadTest
+    public void testAccessTrackTint() {
+        assertEquals(Color.BLACK, mSwitch.getTrackTintList().getDefaultColor());
+        assertEquals(Mode.SRC_ATOP, mSwitch.getTrackTintMode());
+
+        ColorStateList colors = ColorStateList.valueOf(Color.RED);
+        mSwitch.setTrackTintList(colors);
+        mSwitch.setTrackTintMode(Mode.XOR);
+
+        assertSame(colors, mSwitch.getTrackTintList());
+        assertEquals(Mode.XOR, mSwitch.getTrackTintMode());
     }
 }
diff --git a/tests/tests/widget/src/android/widget/cts/ToolbarTest.java b/tests/tests/widget/src/android/widget/cts/ToolbarTest.java
index 0fd98c0..7f9690c 100644
--- a/tests/tests/widget/src/android/widget/cts/ToolbarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToolbarTest.java
@@ -17,6 +17,9 @@
 package android.widget.cts;
 
 import android.app.Instrumentation;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
@@ -24,6 +27,7 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
+import android.widget.ListPopupWindow;
 import android.widget.Toolbar;
 import android.widget.cts.util.TestUtils;
 import android.widget.cts.util.ViewTestUtils;
@@ -46,6 +50,16 @@
         mMainToolbar = mActivity.getMainToolbar();
     }
 
+    public void testConstructor() {
+        new Toolbar(mActivity);
+
+        new Toolbar(mActivity, null);
+
+        new Toolbar(mActivity, null, android.R.attr.toolbarStyle);
+
+        new Toolbar(mActivity, null, 0, android.R.style.Widget_Material_Toolbar);
+    }
+
     public void testTitleAndSubtitleContent() {
         // Note that this method is *not* annotated to run on the UI thread, and every
         // call to setTitle / setSubtitle is wrapped to wait until the next draw pass
@@ -72,6 +86,30 @@
         assertEquals("New subtitle", mMainToolbar.getSubtitle());
     }
 
+    public void testTitleAndSubtitleAppearance() {
+        final Instrumentation instrumentation = getInstrumentation();
+
+        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+                () -> mMainToolbar.setTitle(R.string.toolbar_title));
+        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+                () -> mMainToolbar.setSubtitle(R.string.toolbar_subtitle));
+
+        // Since there are no APIs to get reference to the underlying implementation of
+        // title and subtitle, here we are testing that calling the relevant APIs doesn't crash
+
+        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+                () -> mMainToolbar.setTitleTextColor(Color.RED));
+        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+                () -> mMainToolbar.setSubtitleTextColor(Color.BLUE));
+
+        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+                () -> mMainToolbar.setTitleTextAppearance(
+                        mActivity, R.style.TextAppearance_NotColors));
+        ViewTestUtils.runOnMainAndDrawSync(instrumentation, mMainToolbar,
+                () -> mMainToolbar.setSubtitleTextAppearance(
+                        mActivity, R.style.TextAppearance_WithColor));
+    }
+
     @UiThreadTest
     public void testGetTitleMargins() {
         assertEquals(5, mMainToolbar.getTitleMarginStart());
@@ -326,4 +364,22 @@
         assertEquals(40, mMainToolbar.getContentInsetRight());
         assertEquals(20, mMainToolbar.getContentInsetEnd());
     }
+
+    @UiThreadTest
+    public void testPopupTheme() {
+        mMainToolbar.setPopupTheme(R.style.ToolbarPopupTheme_Test);
+        assertEquals(R.style.ToolbarPopupTheme_Test, mMainToolbar.getPopupTheme());
+    }
+
+    public void testNavigationOnClickListener() {
+        View.OnClickListener mockListener = mock(View.OnClickListener.class);
+        mMainToolbar.setNavigationOnClickListener(mockListener);
+
+        verify(mockListener, never()).onClick(any(View.class));
+
+        getInstrumentation().runOnMainSync(() -> mMainToolbar.getNavigationView().performClick());
+        verify(mockListener, times(1)).onClick(any(View.class));
+
+        verifyNoMoreInteractions(mockListener);
+    }
 }
diff --git a/tests/vr/Android.mk b/tests/vr/Android.mk
new file mode 100644
index 0000000..04644a0
--- /dev/null
+++ b/tests/vr/Android.mk
@@ -0,0 +1,39 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsVrTestCases
+
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := optional
+
+# Include both the 32 and 64 bit versions
+LOCAL_MULTILIB := both
+
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/vr/AndroidManifest.xml b/tests/vr/AndroidManifest.xml
new file mode 100644
index 0000000..877d846
--- /dev/null
+++ b/tests/vr/AndroidManifest.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.vr.cts"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-sdk android:minSdkVersion="14" />
+    <uses-feature android:glEsVersion="0x00020000"/>
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="android.vr.cts" >
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+    <application
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:hardwareAccelerated="false" >
+
+         <activity
+            android:label="@string/app_name"
+            android:name="android.vr.cts.OpenGLESActivity">
+         </activity>
+         <activity android:name=".CtsActivity"
+                  android:label="CtsActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+         <uses-library  android:name="android.test.runner" />
+    </application>
+
+</manifest>
diff --git a/tests/vr/AndroidTest.xml b/tests/vr/AndroidTest.xml
new file mode 100644
index 0000000..a687370
--- /dev/null
+++ b/tests/vr/AndroidTest.xml
@@ -0,0 +1,23 @@
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS VR test cases">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsVrTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.vr.cts" />
+    </test>
+</configuration>
diff --git a/tests/vr/res/drawable-hdpi/ic_launcher.png b/tests/vr/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..8074c4c
--- /dev/null
+++ b/tests/vr/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/tests/vr/res/drawable-ldpi/ic_launcher.png b/tests/vr/res/drawable-ldpi/ic_launcher.png
new file mode 100644
index 0000000..1095584
--- /dev/null
+++ b/tests/vr/res/drawable-ldpi/ic_launcher.png
Binary files differ
diff --git a/tests/vr/res/drawable-mdpi/ic_launcher.png b/tests/vr/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..a07c69f
--- /dev/null
+++ b/tests/vr/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/tests/vr/res/layout/main.xml b/tests/vr/res/layout/main.xml
new file mode 100644
index 0000000..fc2dfc1
--- /dev/null
+++ b/tests/vr/res/layout/main.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical" >
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/vr/res/values/strings.xml b/tests/vr/res/values/strings.xml
new file mode 100644
index 0000000..e87ad4a
--- /dev/null
+++ b/tests/vr/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <string name="app_name">CtsVrTestCases</string>
+
+</resources>
diff --git a/tests/vr/src/android/vr/cts/CtsActivity.java b/tests/vr/src/android/vr/cts/CtsActivity.java
new file mode 100644
index 0000000..33fff08
--- /dev/null
+++ b/tests/vr/src/android/vr/cts/CtsActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.vr.cts;
+
+import android.app.Activity;
+
+public class CtsActivity extends Activity {
+
+}
diff --git a/tests/vr/src/android/vr/cts/OpenGLESActivity.java b/tests/vr/src/android/vr/cts/OpenGLESActivity.java
new file mode 100644
index 0000000..75eff00
--- /dev/null
+++ b/tests/vr/src/android/vr/cts/OpenGLESActivity.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.vr.cts;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.opengl.EGL14;
+import android.opengl.GLES20;
+import android.opengl.GLSurfaceView;
+import android.opengl.GLSurfaceView.Renderer;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Window;
+import android.view.WindowManager;
+
+import java.lang.InterruptedException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+
+public class OpenGLESActivity extends Activity {
+    private static final String TAG = "OpenGLESActivity";
+
+    public static final String EXTRA_VIEW_INDEX = "viewIndex";
+    public static final String EXTRA_PROTECTED = "protected";
+    public static final String EXTRA_PRIORITY = "priority";
+    public static final String EXTRA_LATCH_COUNT = "latchCount";
+
+
+    // Note that the final extension will use value 0x32C0.
+    public static final int EGL_PROTECTED_CONTENT_EXT = 0x32E0;
+
+    // Context priority enums are not exposed in Java.
+    public static final int EGL_CONTEXT_PRIORITY_LEVEL_IMG = 0x3100;
+
+    OpenGLES20View mView;
+    Renderer mRenderer;
+    int mRendererType;
+    private CountDownLatch mLatch;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Window window = getWindow();
+        window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+
+        int viewIndex = getIntent().getIntExtra(EXTRA_VIEW_INDEX, -1);
+        int protectedAttribute = getIntent().getIntExtra(EXTRA_PROTECTED, -1);
+        int priorityAttribute = getIntent().getIntExtra(EXTRA_PRIORITY, -1);
+        int latchCount = getIntent().getIntExtra(EXTRA_LATCH_COUNT, 1);
+        mLatch = new CountDownLatch(latchCount);
+        mView = new OpenGLES20View(this, viewIndex, protectedAttribute, priorityAttribute,
+            mLatch);
+
+        setContentView(mView);
+    }
+
+    public int glGetError() {
+        return ((RendererBasicTest)mRenderer).mError;
+    }
+
+    public static void checkEglError(String msg) {
+        boolean failed = false;
+        int error;
+        while ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS) {
+            Log.e(TAG, msg + ": EGL error: 0x" + Integer.toHexString(error));
+            failed = true;
+        }
+        if (failed) {
+            throw new RuntimeException("EGL error encountered (EGL error: 0x" +
+                Integer.toHexString(error) + ")");
+        }
+    }
+
+    public void runOnGlThread(Runnable r) throws Throwable {
+        CountDownLatch fence = new CountDownLatch(1);
+        RunSignalAndCatch wrapper = new RunSignalAndCatch(r, fence);
+
+        mView.queueEvent(wrapper);
+        fence.await(5000, TimeUnit.MILLISECONDS);
+        if (wrapper.error != null) {
+            throw wrapper.error;
+        }
+    }
+
+    public static boolean contextHasAttributeWithValue(int attribute, int value) {
+        int[] values = new int[1];
+        EGL14.eglQueryContext(EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY),
+            EGL14.eglGetCurrentContext(), attribute, values, 0);
+        checkEglError("eglQueryContext");
+        return values[0] == value;
+    }
+
+    public static boolean surfaceHasAttributeWithValue(int attribute, int value) {
+        int[] values = new int[1];
+        EGL14.eglQuerySurface(EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY),
+            EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW), attribute, values, 0);
+        checkEglError("eglQueryContext");
+        return values[0] == value;
+    }
+
+    public static void setSurfaceAttribute(int attribute, int value) {
+        int[] values = new int[1];
+        EGL14.eglSurfaceAttrib(EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY),
+            EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW), attribute, value);
+        checkEglError("eglSurfaceAttrib");
+    }
+
+    public boolean waitForFrameDrawn() {
+        boolean result = false;
+        try {
+            result = mLatch.await(1L, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            // just return false
+        }
+        return result;
+    }
+
+    public boolean supportsVrHighPerformance() {
+        PackageManager pm = getPackageManager();
+        return pm.hasSystemFeature(PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE);
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        if (mView != null) {
+            mView.onPause();
+        }
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        if (mView != null) {
+            mView.onResume();
+        }
+    }
+
+    private class RunSignalAndCatch implements Runnable {
+        public Throwable error;
+        private Runnable mRunnable;
+        private CountDownLatch mFence;
+
+        RunSignalAndCatch(Runnable run, CountDownLatch fence) {
+            mRunnable = run;
+            mFence = fence;
+        }
+
+        @Override
+        public void run() {
+            try {
+                mRunnable.run();
+            } catch (Throwable t) {
+                error = t;
+            } finally {
+                mFence.countDown();
+            }
+        }
+    }
+
+    class OpenGLES20View extends GLSurfaceView {
+
+        public OpenGLES20View(Context context, int index, int protectedAttribute,
+            int priorityAttribute, CountDownLatch latch) {
+            super(context);
+            setEGLContextClientVersion(2);
+
+            if (protectedAttribute == 1) {
+                setEGLContextFactory(new ProtectedContextFactory());
+                setEGLWindowSurfaceFactory(new ProtectedWindowSurfaceFactory());
+            } else if (priorityAttribute != 0) {
+                setEGLContextFactory(new PriorityContextFactory(priorityAttribute));
+            }
+
+            if (index == 1) {
+                mRenderer = new RendererBasicTest(latch);
+            } else  if (index == 2) {
+                mRenderer = new RendererProtectedTexturesTest(latch);
+            } else  if (index == 3) {
+                mRenderer = new RendererRefreshRateTest(latch);
+            } else {
+                throw new RuntimeException();
+            }
+            setRenderer(mRenderer);
+        }
+
+        @Override
+        public void setEGLContextClientVersion(int version) {
+            super.setEGLContextClientVersion(version);
+        }
+    }
+
+    private class PriorityContextFactory implements GLSurfaceView.EGLContextFactory {
+        private int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+        private int mEGLContextClientVersion = 2;
+
+        private int mPriority;
+
+        PriorityContextFactory(int priorityAttribute) {
+            super();
+            mPriority = priorityAttribute;
+        }
+
+        public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config) {
+            int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, mEGLContextClientVersion,
+                EGL_CONTEXT_PRIORITY_LEVEL_IMG,  mPriority, EGL10.EGL_NONE };
+
+            EGLContext context = egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT,
+                attrib_list);
+            if (context == EGL10.EGL_NO_CONTEXT) {
+              Log.e(TAG, "Error creating EGL context.");
+            }
+            checkEglError("eglCreateContext");
+            return context;
+        }
+
+        public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
+            if (!egl.eglDestroyContext(display, context)) {
+              Log.e("DefaultContextFactory", "display:" + display + " context: " + context);
+            }
+          }
+    }
+
+    private class ProtectedContextFactory implements GLSurfaceView.EGLContextFactory {
+        private int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+        private int mEGLContextClientVersion = 2;
+
+        public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config) {
+            int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, mEGLContextClientVersion,
+                EGL_PROTECTED_CONTENT_EXT,  EGL14.EGL_TRUE,
+                EGL10.EGL_NONE };
+
+            EGLContext context = egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT,
+                attrib_list);
+            if (context == EGL10.EGL_NO_CONTEXT) {
+              Log.e(TAG, "Error creating EGL context.");
+            }
+            checkEglError("eglCreateContext");
+            return context;
+        }
+
+        public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
+            if (!egl.eglDestroyContext(display, context)) {
+              Log.e("DefaultContextFactory", "display:" + display + " context: " + context);
+            }
+          }
+    }
+
+    private static class ProtectedWindowSurfaceFactory implements GLSurfaceView.EGLWindowSurfaceFactory {
+
+      public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display,
+                                            EGLConfig config, Object nativeWindow) {
+        EGLSurface result = null;
+        try {
+          int[] attrib_list = { EGL_PROTECTED_CONTENT_EXT,  EGL14.EGL_TRUE, EGL10.EGL_NONE };
+          result = egl.eglCreateWindowSurface(display, config, nativeWindow, attrib_list);
+          checkEglError("eglCreateWindowSurface");
+        } catch (IllegalArgumentException e) {
+          Log.e(TAG, "eglCreateWindowSurface", e);
+        }
+        return result;
+      }
+
+      public void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface) {
+        egl.eglDestroySurface(display, surface);
+      }
+    }
+}
diff --git a/tests/vr/src/android/vr/cts/RendererBasicTest.java b/tests/vr/src/android/vr/cts/RendererBasicTest.java
new file mode 100644
index 0000000..9e1b2a4
--- /dev/null
+++ b/tests/vr/src/android/vr/cts/RendererBasicTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.vr.cts;
+
+import android.opengl.GLES20;
+import android.opengl.GLSurfaceView;
+import android.opengl.GLSurfaceView.Renderer;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.util.concurrent.CountDownLatch;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+public class RendererBasicTest implements GLSurfaceView.Renderer {
+    private String vertexShaderCode =
+              "attribute vec4 vPosition; \n"
+            + "void main(){              \n" +
+                 "gl_Position = vPosition; \n"
+            + "}                         \n";
+
+    private String fragmentShaderCode = "precision mediump float;  \n"
+            + "void main(){              \n"
+            + " gl_FragColor = vec4 (0.63671875, 0.76953125, 0.22265625, 1.0); \n"
+            + "}  \n";
+
+
+    FloatBuffer floatBuffer;
+    int mProgram;
+    int maPositionHandle;
+    float[] mColorOne = new float[4];
+
+    int[] mShaderCount = null;
+    int mError;
+
+    // child may need to manipulate them directly
+    protected CountDownLatch mLatch;
+    protected boolean mDrawn = false;
+
+    public RendererBasicTest(CountDownLatch latch) {
+        mLatch = latch;
+    }
+
+    @Override
+    public void onSurfaceChanged(GL10 gl, int width, int height) {
+    }
+
+    public int loadShader(int type, String shaderCode) {
+        int shader = GLES20.glCreateShader(type);
+        GLES20.glShaderSource(shader, shaderCode);
+        GLES20.glCompileShader(shader);
+        return shader;
+    }
+
+    @Override
+    public void onDrawFrame(GL10 gl) {
+        if (mDrawn) {
+            return;
+        }
+        mDrawn = true;
+        doOnDrawFrame(gl);
+        mLatch.countDown();
+    }
+
+    public void doOnDrawFrame(GL10 gl) {
+        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
+        GLES20.glUseProgram(mProgram);
+
+        GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT,
+                false, 12, floatBuffer);
+        GLES20.glEnableVertexAttribArray(maPositionHandle);
+        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
+        mShaderCount = new int[1];
+        int[] shaders = new int[10];
+        GLES20.glGetAttachedShaders(mProgram, 10, mShaderCount, 0, shaders, 0);
+    }
+
+    @Override
+    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+        GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
+        initShapes();
+        int vertexShaderOne = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
+        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
+        mProgram =  GLES20.glCreateProgram();
+        GLES20.glAttachShader(mProgram, vertexShaderOne);
+        GLES20.glAttachShader(mProgram, fragmentShader);
+        GLES20.glLinkProgram(mProgram);
+        int[] linkStatus = new int[1];
+        GLES20.glGetProgramiv(mProgram, GLES20.GL_LINK_STATUS, linkStatus, 0);
+        if (linkStatus[0] != GLES20.GL_TRUE) {
+           //do nothing
+        }
+
+    }
+
+    public void initShapes(){
+        float triangleCoords[] = {   -0.5f, -0.25f, 0,
+                 0.5f, -0.25f, 0,
+                 0.0f,  0.559016994f, 0};
+        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(triangleCoords.length * 4);
+        byteBuffer.order(ByteOrder.nativeOrder());
+        floatBuffer = byteBuffer.asFloatBuffer();
+        floatBuffer.put(triangleCoords);
+        floatBuffer.position(0);
+    }
+}
diff --git a/tests/vr/src/android/vr/cts/RendererProtectedTexturesTest.java b/tests/vr/src/android/vr/cts/RendererProtectedTexturesTest.java
new file mode 100644
index 0000000..e53dfe0
--- /dev/null
+++ b/tests/vr/src/android/vr/cts/RendererProtectedTexturesTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.vr.cts;
+
+import java.nio.IntBuffer;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.opengl.GLES20;
+
+import java.util.concurrent.CountDownLatch;
+
+public class RendererProtectedTexturesTest extends RendererBasicTest {
+
+    private String vertexShaderCode = "attribute vec4 vPosition; \n"
+            + "void main(){              \n"
+            +    "gl_Position = vPosition; \n"
+            + "}                         \n";
+
+    private String fragmentShaderCode = "precision mediump float;  \n"
+            + "sampler2D protectedTexture;\n"
+            + "void main(){              \n"
+            + " gl_FragColor = texture2D(protectedTexture, vec2(0.76953125, 0.22265625)); \n"
+            + "}  \n";
+
+    // TODO: Update this value when the extension is ratified.
+    public static int GL_CONTEXT_FLAG_PROTECTED_CONTENT_BIT = 0x00000016;
+    public static int GL_TEXTURE_PROTECTED_EXT = 0x8BFA;
+
+    private IntBuffer mTexture;
+
+    public RendererProtectedTexturesTest(CountDownLatch latch) {
+        super(latch);
+    }
+
+    @Override
+    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+        GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
+        initShapes();
+        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
+        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
+        mProgram = GLES20.glCreateProgram();
+        GLES20.glAttachShader(mProgram, vertexShader);
+        GLES20.glAttachShader(mProgram, fragmentShader);
+        GLES20.glLinkProgram(mProgram);
+        int[] linkStatus = new int[1];
+        GLES20.glGetProgramiv(mProgram, GLES20.GL_LINK_STATUS, linkStatus, 0);
+        if (linkStatus[0] != GLES20.GL_TRUE) {
+           //do nothing
+        }
+
+        // Create and bind a protected texture.
+        mTexture = IntBuffer.allocate(1);
+        GLES20.glGenTextures(1, mTexture);
+        GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
+        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexture.get(0));
+        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GL_TEXTURE_PROTECTED_EXT, GLES20.GL_TRUE);
+        int loc = GLES20.glGetUniformLocation(mProgram, "protectedTexture");
+        GLES20.glUniform1i(loc, 2);
+    }
+}
+
diff --git a/tests/vr/src/android/vr/cts/RendererRefreshRateTest.java b/tests/vr/src/android/vr/cts/RendererRefreshRateTest.java
new file mode 100644
index 0000000..30a0e3a
--- /dev/null
+++ b/tests/vr/src/android/vr/cts/RendererRefreshRateTest.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.vr.cts;
+
+import java.util.concurrent.CountDownLatch;
+import javax.microedition.khronos.opengles.GL10;
+
+public class RendererRefreshRateTest extends RendererBasicTest {
+
+    public RendererRefreshRateTest(CountDownLatch latch) {
+        super(latch);
+    }
+
+    @Override
+    public void onDrawFrame(GL10 gl) {
+        doOnDrawFrame(gl);
+        mLatch.countDown();
+    }
+}
diff --git a/tests/vr/src/android/vr/cts/VrCpuTest.java b/tests/vr/src/android/vr/cts/VrCpuTest.java
new file mode 100644
index 0000000..f015899
--- /dev/null
+++ b/tests/vr/src/android/vr/cts/VrCpuTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.vr.cts;
+
+import android.content.pm.PackageManager;
+import android.os.Process;
+import android.test.ActivityInstrumentationTestCase2;
+
+public class VrCpuTest extends ActivityInstrumentationTestCase2<CtsActivity> {
+    private CtsActivity mActivity;
+
+    public VrCpuTest() {
+        super(CtsActivity.class);
+    }
+
+    public void testHasAtLeastTwoCores() {
+        mActivity = getActivity();
+        if (mActivity.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE)) {
+            assertTrue(Runtime.getRuntime().availableProcessors() >= 2);
+        }
+    }
+
+    public void testHasExclusiveCores() {
+        mActivity = getActivity();
+        if (mActivity.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE)) {
+            int[] excl_cores = Process.getExclusiveCores();
+            assertTrue(excl_cores.length >= 1);
+        }
+    }
+}
diff --git a/tests/vr/src/android/vr/cts/VrDisplayTest.java b/tests/vr/src/android/vr/cts/VrDisplayTest.java
new file mode 100644
index 0000000..6b8b302
--- /dev/null
+++ b/tests/vr/src/android/vr/cts/VrDisplayTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.vr.cts;
+
+import android.content.Context;
+import android.content.Intent;
+import android.opengl.EGL14;
+import android.opengl.GLES32;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.DisplayMetrics;
+import android.view.WindowManager;
+
+import java.nio.IntBuffer;
+
+public class VrDisplayTest extends ActivityInstrumentationTestCase2<OpenGLESActivity> {
+
+    private OpenGLESActivity mActivity;
+
+    public VrDisplayTest() {
+        super(OpenGLESActivity.class);
+    }
+
+    private OpenGLESActivity getGlEsActivity(int latchCount, int viewIndex) {
+        Intent intent = new Intent();
+        intent.putExtra(OpenGLESActivity.EXTRA_LATCH_COUNT, latchCount);
+        intent.putExtra(OpenGLESActivity.EXTRA_VIEW_INDEX, viewIndex);
+        intent.putExtra(OpenGLESActivity.EXTRA_PROTECTED, 0);
+        intent.putExtra(OpenGLESActivity.EXTRA_PRIORITY, 0);
+        setActivityIntent(intent);
+        OpenGLESActivity activity = getActivity();
+        if (latchCount == 1) {
+          assertTrue(activity.waitForFrameDrawn());
+        }
+        return activity;
+    }
+
+    /**
+     * Tests that the refresh rate is at least 60Hz.
+     */
+    public void testRefreshRateIsAtLeast60Hz() throws Throwable {
+        final int NUM_FRAMES = 200;
+        mActivity = getGlEsActivity(NUM_FRAMES, 3);
+        if (!mActivity.supportsVrHighPerformance())
+            return;
+
+        long startNanos = System.nanoTime();
+
+        // Render a few hundred frames.
+        int error;
+        while (!mActivity.waitForFrameDrawn());
+        error = mActivity.glGetError();
+        assertEquals(GLES32.GL_NO_ERROR, error);
+        long endNanos = System.nanoTime();
+
+        double fps = NUM_FRAMES / (double)(endNanos - startNanos) * 1e9;
+        assertTrue(fps >= 59.);
+    }
+
+    /**
+     * Tests that the display resolution is at least 1080p.
+     */
+    public void testDisplayResolution() {
+        mActivity = getGlEsActivity(1, 1);
+        if (!mActivity.supportsVrHighPerformance())
+            return;
+
+        WindowManager windowManager = (WindowManager)mActivity.getSystemService(
+            Context.WINDOW_SERVICE);
+        DisplayMetrics metrics = new DisplayMetrics();
+
+        // Find the real screen size.
+        int displayWidth;
+        int displayHeight;
+        windowManager.getDefaultDisplay().getRealMetrics(metrics);
+        if (metrics.widthPixels > metrics.heightPixels) {
+          displayWidth = metrics.widthPixels;
+          displayHeight = metrics.heightPixels;
+        } else {
+          displayWidth = metrics.heightPixels;
+          displayHeight = metrics.widthPixels;
+        }
+        assertTrue(displayWidth >= 1920);
+        assertTrue(displayHeight >= 1080);
+    }
+}
diff --git a/tests/vr/src/android/vr/cts/VrExtensionBehaviorTest.java b/tests/vr/src/android/vr/cts/VrExtensionBehaviorTest.java
new file mode 100644
index 0000000..0641bfb
--- /dev/null
+++ b/tests/vr/src/android/vr/cts/VrExtensionBehaviorTest.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.vr.cts;
+
+import android.content.Intent;
+import android.opengl.EGL14;
+import android.opengl.GLES32;
+import android.test.ActivityInstrumentationTestCase2;
+
+import java.nio.IntBuffer;
+
+public class VrExtensionBehaviorTest extends ActivityInstrumentationTestCase2<OpenGLESActivity> {
+
+    private static final int EGL_CONTEXT_PRIORITY_HIGH_IMG = 0x3101;
+    private static final int EGL_CONTEXT_PRIORITY_MEDIUM_IMG = 0x3102;
+    private static final int EGL_CONTEXT_PRIORITY_LOW_IMG = 0x3103;
+
+    private static final int EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID = 0x314C;
+
+    private OpenGLESActivity mActivity;
+
+    public VrExtensionBehaviorTest() {
+        super(OpenGLESActivity.class);
+    }
+
+    private OpenGLESActivity getGlEsActivity(int viewIndex, int createProtected,
+        int priorityAttribute) {
+        Intent intent = new Intent();
+        intent.putExtra(OpenGLESActivity.EXTRA_VIEW_INDEX, viewIndex);
+        intent.putExtra(OpenGLESActivity.EXTRA_PROTECTED, createProtected);
+        intent.putExtra(OpenGLESActivity.EXTRA_PRIORITY, priorityAttribute);
+        setActivityIntent(intent);
+        OpenGLESActivity activity = getActivity();
+        assertTrue(activity.waitForFrameDrawn());
+        return activity;
+    }
+
+    /**
+     * Tests that protected content contexts and surfaces can be created.
+     */
+    public void testProtectedContent() throws Throwable {
+        mActivity = getGlEsActivity(1, 1, 0);
+        if (!mActivity.supportsVrHighPerformance())
+            return;
+
+        int error = mActivity.glGetError();
+        assertEquals(GLES32.GL_NO_ERROR, error);
+
+        mActivity.runOnGlThread(new Runnable() {
+            public void run() {
+                // Check that both the context and surface have the right attribute set.
+                assertTrue("Unable to validate protected context",
+                    OpenGLESActivity.contextHasAttributeWithValue(
+                        OpenGLESActivity.EGL_PROTECTED_CONTENT_EXT, EGL14.EGL_TRUE));
+                assertTrue("Unable to validate protected surface",
+                    OpenGLESActivity.surfaceHasAttributeWithValue(
+                        OpenGLESActivity.EGL_PROTECTED_CONTENT_EXT, EGL14.EGL_TRUE));
+            }
+        });
+    }
+
+    /**
+     * Tests that textures can be marked as protected.
+     */
+    public void testProtectedTextures() throws Throwable {
+        mActivity = getGlEsActivity(2, 1, 0);
+        if (!mActivity.supportsVrHighPerformance())
+            return;
+
+        int error = mActivity.glGetError();
+        assertEquals(GLES32.GL_NO_ERROR, error);
+
+        mActivity.runOnGlThread(new Runnable() {
+            public void run() {
+                // Check that both the context and surface have the right attribute set.
+                int[] values = new int[1];
+                GLES32.glGetIntegerv(GLES32.GL_CONTEXT_FLAGS, values, 0);
+                assertTrue("Context is not a protected context",
+                    (values[0] & RendererProtectedTexturesTest.GL_CONTEXT_FLAG_PROTECTED_CONTENT_BIT) != 0);
+
+                values[0] = 0;
+                GLES32.glGetTexParameteriv(GLES32.GL_TEXTURE_2D,
+                    RendererProtectedTexturesTest.GL_TEXTURE_PROTECTED_EXT, values, 0);
+                assertEquals("Texture is not marked as protected", GLES32.GL_TRUE, values[0]);
+            }
+        });
+    }
+
+    /**
+     * Tests that context priority can be set to high.
+     */
+    public void testContextPriorityHigh() throws Throwable {
+        runContextPriorityTest(EGL_CONTEXT_PRIORITY_HIGH_IMG);
+    }
+
+    /**
+     * Tests that context priority can be set to medium.
+     */
+    public void testContextPriorityMedium() throws Throwable {
+        runContextPriorityTest(EGL_CONTEXT_PRIORITY_MEDIUM_IMG);
+    }
+
+    /**
+     * Tests that context priority can be set to low.
+     */
+    public void testContextPriorityLow() throws Throwable {
+        runContextPriorityTest(EGL_CONTEXT_PRIORITY_LOW_IMG);
+    }
+
+    /**
+     * Tests that context priority can be set to low.
+     */
+    public void testMutableRenderBuffer() throws Throwable {
+
+        mActivity = getGlEsActivity(1, 0, 0);
+        if (!mActivity.supportsVrHighPerformance())
+            return;
+
+        int error = mActivity.glGetError();
+        assertEquals(GLES32.GL_NO_ERROR, error);
+
+        mActivity.runOnGlThread(new Runnable() {
+            public void run() {
+                OpenGLESActivity.setSurfaceAttribute(EGL14.EGL_RENDER_BUFFER,
+                    EGL14.EGL_SINGLE_BUFFER);
+                OpenGLESActivity.setSurfaceAttribute(EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID,
+                    EGL14.EGL_TRUE);
+                swapBuffers();
+                assertTrue("Unable to enable single buffered mode",
+                    OpenGLESActivity.contextHasAttributeWithValue(
+                        EGL14.EGL_RENDER_BUFFER, EGL14.EGL_SINGLE_BUFFER));
+                assertTrue("Unable to enable single buffered mode",
+                    OpenGLESActivity.contextHasAttributeWithValue(
+                        EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID, EGL14.EGL_TRUE));
+
+                OpenGLESActivity.setSurfaceAttribute(EGL14.EGL_RENDER_BUFFER,
+                    EGL14.EGL_BACK_BUFFER);
+                swapBuffers();
+                assertTrue("Unable to disable single buffered mode",
+                    OpenGLESActivity.contextHasAttributeWithValue(
+                        EGL14.EGL_RENDER_BUFFER, EGL14.EGL_BACK_BUFFER));
+            }
+        });
+    }
+
+    /**
+     * Runs a context priority test.
+     */
+    private void runContextPriorityTest(int priority) throws Throwable {
+        mActivity = getGlEsActivity(1, 0, priority);
+        if (!mActivity.supportsVrHighPerformance())
+            return;
+
+        int error = mActivity.glGetError();
+        assertEquals(GLES32.GL_NO_ERROR, error);
+
+        mActivity.runOnGlThread(new Runnable() {
+            public void run() {
+                assertTrue("Unable to set context priority to " + Integer.toHexString(priority),
+                    OpenGLESActivity.contextHasAttributeWithValue(
+                        OpenGLESActivity.EGL_CONTEXT_PRIORITY_LEVEL_IMG, priority));
+            }
+        });
+    }
+
+    /**
+     * Swaps EGL buffers.
+     */
+    private void swapBuffers() {
+        EGL14.eglSwapBuffers(EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY),
+            EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW));
+    }
+}
diff --git a/tests/vr/src/android/vr/cts/VrSensorsTest.java b/tests/vr/src/android/vr/cts/VrSensorsTest.java
new file mode 100644
index 0000000..1f44def
--- /dev/null
+++ b/tests/vr/src/android/vr/cts/VrSensorsTest.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.vr.cts;
+
+import android.content.pm.PackageManager;
+import android.test.AndroidTestCase;
+
+/**
+ * Tests related to sensors and VR.
+ */
+public class VrSensorsTest extends AndroidTestCase {
+    private static final String TAG = "VrSensorsTest";
+
+    /**
+     * Tests creating a protected context.
+     */
+    public void testHiFiSensorsAreSupported() {
+        PackageManager pm = getContext().getPackageManager();
+        assertTrue(!pm.hasSystemFeature(PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE) ||
+            pm.hasSystemFeature(PackageManager.FEATURE_HIFI_SENSORS));
+    }
+}
diff --git a/tools/cts-device-info/Android.mk b/tools/cts-device-info/Android.mk
index 99dc6d1..4b43d39 100644
--- a/tools/cts-device-info/Android.mk
+++ b/tools/cts-device-info/Android.mk
@@ -24,7 +24,8 @@
 DEVICE_INFO_PERMISSIONS :=
 
 DEVICE_INFO_ACTIVITIES := \
-    com.android.compatibility.common.deviceinfo.GlesStubActivity
+    com.android.compatibility.common.deviceinfo.GlesStubActivity \
+    com.android.cts.deviceinfo.CameraDeviceInfo
 
 LOCAL_PACKAGE_NAME := CtsDeviceInfo
 
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/CameraDeviceInfo.java b/tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java
similarity index 94%
rename from common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/CameraDeviceInfo.java
rename to tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java
index 2cc4478..41afdb9eb 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/CameraDeviceInfo.java
+++ b/tools/cts-device-info/src/com/android/cts/deviceinfo/CameraDeviceInfo.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.compatibility.common.deviceinfo;
+package com.android.cts.deviceinfo;
 
 import android.content.Context;
 import android.graphics.Rect;
@@ -32,6 +32,7 @@
 import android.util.SizeF;
 import android.util.Range;
 
+import com.android.compatibility.common.deviceinfo.DeviceInfo;
 import com.android.compatibility.common.util.DeviceInfoStore;
 
 import java.lang.reflect.Array;
@@ -415,36 +416,25 @@
         store.addResult("profile_qcif", CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_QCIF));
         store.addResult("profile_qvga", CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_QVGA));
 
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.L) {
-            // query camera devices and store each camera's characteristics
-            CameraManager cameraManager = (CameraManager)
-                    getContext().getSystemService(Context.CAMERA_SERVICE);
-            try {
-                String[] cameraIdList = cameraManager.getCameraIdList();
-                store.addResult("num_of_camera", cameraIdList.length);
-                if (cameraIdList.length > 0) {
-                    CameraCharacteristicsStorer charsStorer =
-                            new CameraCharacteristicsStorer(cameraManager, store);
-                    store.startArray("per_camera_info");
-                    for (int i = 0; i < cameraIdList.length; i++) {
-                        charsStorer.storeCameraInfo(cameraIdList[i]);
-                    }
-                    store.endArray(); // per_camera_info
+        CameraManager cameraManager = (CameraManager)
+                getContext().getSystemService(Context.CAMERA_SERVICE);
+        try {
+            String[] cameraIdList = cameraManager.getCameraIdList();
+            store.addResult("num_of_camera", cameraIdList.length);
+            if (cameraIdList.length > 0) {
+                CameraCharacteristicsStorer charsStorer =
+                        new CameraCharacteristicsStorer(cameraManager, store);
+                store.startArray("per_camera_info");
+                for (int i = 0; i < cameraIdList.length; i++) {
+                    charsStorer.storeCameraInfo(cameraIdList[i]);
                 }
-            } catch (CameraAccessException e) {
-                Log.e(TAG,
-                        "Unable to get camera camera ID list, error: "
-                                + e.getMessage());
+                store.endArray(); // per_camera_info
             }
-        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
-            // Only supports Camera API1
-            int numCameras = Camera.getNumberOfCameras();
-            store.addResult("num_of_camera", numCameras);
-        } else {
-            // No Camera number query support
-            store.addResult("num_of_camera", 0);
+        } catch (CameraAccessException e) {
+            Log.e(TAG,
+                    "Unable to get camera camera ID list, error: "
+                            + e.getMessage());
         }
-
     }
 
     /*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
diff --git a/tools/cts-tradefed/res/config/collect-tests-only.xml b/tools/cts-tradefed/res/config/collect-tests-only.xml
index 1c22b11..9fd7757 100644
--- a/tools/cts-tradefed/res/config/collect-tests-only.xml
+++ b/tools/cts-tradefed/res/config/collect-tests-only.xml
@@ -33,4 +33,7 @@
     <!-- Tell all HostTests to only list the tests -->
     <option name="compatibility:test-arg" value="com.android.tradefed.testtype.HostTest:collect-tests-only:true" />
 
+    <!-- Tell all deqp tests to only list the tests -->
+    <option name="compatibility:test-arg" value="com.drawelements.deqp.runner.DeqpTestRunner:collect-tests-only:true" />
+
 </configuration>
diff --git a/tools/cts-tradefed/res/config/cts-preconditions.xml b/tools/cts-tradefed/res/config/cts-preconditions.xml
index efe8e3f..cc71524 100644
--- a/tools/cts-tradefed/res/config/cts-preconditions.xml
+++ b/tools/cts-tradefed/res/config/cts-preconditions.xml
@@ -51,6 +51,7 @@
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ReportLogCollector">
         <option name="src-dir" value="/sdcard/report-log-files/"/>
         <option name="dest-dir" value="report-log-files/"/>
+        <option name="temp-dir" value="temp-report-logs/"/>
     </target_preparer>
 
 </configuration>
diff --git a/tools/selinux/SELinuxNeverallowTestFrame.py b/tools/selinux/SELinuxNeverallowTestFrame.py
index ee14116..f1219c1 100644
--- a/tools/selinux/SELinuxNeverallowTestFrame.py
+++ b/tools/selinux/SELinuxNeverallowTestFrame.py
@@ -18,7 +18,7 @@
 
 package android.cts.security;
 
-import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.cts.migration.MigrationHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.testtype.DeviceTestCase;
@@ -37,19 +37,19 @@
     private File sepolicyAnalyze;
     private File devicePolicyFile;
 
+    private IBuildInfo mBuild;
+
     /**
      * A reference to the device under test.
      */
     private ITestDevice mDevice;
 
-    private CompatibilityBuildHelper mHelper;
-
     /**
      * {@inheritDoc}
      */
     @Override
     public void setBuild(IBuildInfo build) {
-        mHelper = new CompatibilityBuildHelper(build);
+        mBuild = build;
     }
 
     /**
@@ -63,7 +63,7 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        sepolicyAnalyze = new File(mHelper.getTestsDir(), "sepolicy-analyze");
+        sepolicyAnalyze = MigrationHelper.getTestFile(mBuild, "sepolicy-analyze");
         sepolicyAnalyze.setExecutable(true);
 
         /* obtain sepolicy file from running device */