am 85e2d7f1: am 52abbfc5: Fix typo for media tests in knownfailures

* commit '85e2d7f108c28c4862d5a89e0850cf2011fb8602':
diff --git a/CtsBuild.mk b/CtsBuild.mk
index 86ecde8..dbe93c7 100644
--- a/CtsBuild.mk
+++ b/CtsBuild.mk
@@ -47,7 +47,7 @@
 endef
 
 define cts-get-native-paths
-	$(foreach exe,$(1),$(call intermediates-dir-for,EXECUTABLES,$(exe))/$(exe))
+	$(foreach exe,$(1),$(call intermediates-dir-for,EXECUTABLES,$(exe),,,$(3))/$(exe)$(2))
 endef
 
 define cts-get-package-paths
@@ -61,3 +61,7 @@
 define cts-get-executable-paths
 	$(foreach executable,$(1),$(CTS_TESTCASES_OUT)/$(executable))
 endef
+
+define cts-get-deqp-test-xmls
+	$(foreach api,$(1),$(CTS_TESTCASES_OUT)/com.drawelements.deqp.$(api).xml)
+endef
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index ce67d37..b3b826d 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -69,6 +69,7 @@
     CtsDeviceTaskswitchingControl \
     CtsDeviceUi \
     CtsIntentReceiverApp \
+    CtsIntentSenderApp \
     CtsManagedProfileApp \
     CtsMonkeyApp \
     CtsMonkeyApp2 \
@@ -106,7 +107,6 @@
     CtsAdminTestCases \
     CtsAnimationTestCases \
     CtsAppTestCases \
-    CtsAppWidgetTestCases \
     CtsBluetoothTestCases \
     CtsCalendarcommon2TestCases \
     CtsContentTestCases \
@@ -121,6 +121,7 @@
     CtsGraphicsTestCases \
     CtsGraphics2TestCases \
     CtsHardwareTestCases \
+    CtsJobSchedulerDeviceTestCases \
     CtsJniTestCases \
     CtsKeystoreTestCases \
     CtsLocationTestCases \
@@ -172,18 +173,22 @@
     CtsDevicePolicyManagerTestCases \
     CtsHostJank \
     CtsHostUi \
+    CtsJdwpSecurityHostTestCases \
     CtsMonkeyTestCases \
     CtsThemeHostTestCases \
     CtsSecurityHostTestCases \
     CtsUsbTests
 
-# Native test executables that need to have associated test XMLs.
-cts_native_exes := \
+# List of native tests. For 32 bit targets, assumes that there will be
+# one test executable, and it will end in 32. For 64 bit targets, assumes
+# that there will be two executables, one that ends in 32 for the 32
+# bit executable and one that ends in 64 for the 64 bit executable.
+cts_native_tests := \
     NativeMediaTest_SL \
     NativeMediaTest_XA \
 
 ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x86_64))
-cts_native_exes += bionic-unit-tests-cts
+cts_native_tests += bionic-unit-tests-cts
 endif
 
 cts_ui_tests := \
@@ -191,6 +196,7 @@
 
 cts_device_jars := \
     CtsDeviceJank \
+    CtsJdwpApp \
     CtsPrintInstrument
 
 cts_device_executables := \
@@ -199,25 +205,38 @@
 cts_target_junit_tests := \
     CtsJdwp
 
+cts_deqp_test_apis := \
+    gles3 \
+    gles31
+
 # All the files that will end up under the repository/testcases
 # directory of the final CTS distribution.
 CTS_TEST_CASES := $(call cts-get-lib-paths,$(cts_host_libraries)) \
     $(call cts-get-package-paths,$(cts_test_packages)) \
-    $(call cts-get-native-paths,$(cts_native_exes)) \
     $(call cts-get-ui-lib-paths,$(cts_ui_tests)) \
     $(call cts-get-ui-lib-paths,$(cts_device_jars)) \
     $(call cts-get-ui-lib-paths,$(cts_target_junit_tests)) \
     $(call cts-get-executable-paths,$(cts_device_executables))
 
+# NOTE: If compiling on a 64 bit target, TARGET_2ND_ARCH will be non-empty
+# and will cause the function to expand to the secondary arch object
+# directory. If compiling on a 32 bit target, TARGET_2ND_ARCH will be
+# empty and will cause the function to expand to the primary arch object
+# directory.
+CTS_TEST_CASES += $(call cts-get-native-paths,$(cts_native_tests),32,$(TARGET_2ND_ARCH))
+
+ifeq ($(TARGET_IS_64_BIT),true)
+CTS_TEST_CASES += $(call cts-get-native-paths,$(cts_native_tests),64)
+endif
+
 # All the XMLs that will end up under the repository/testcases
 # and that need to be created before making the final CTS distribution.
 CTS_TEST_XMLS := $(call cts-get-test-xmls,$(cts_host_libraries)) \
     $(call cts-get-test-xmls,$(cts_test_packages)) \
-    $(call cts-get-test-xmls,$(cts_native_exes)) \
+    $(call cts-get-test-xmls,$(cts_native_tests)) \
     $(call cts-get-test-xmls,$(cts_target_junit_tests)) \
     $(call cts-get-test-xmls,$(cts_ui_tests)) \
-    external/deqp/android/cts/com.drawelements.deqp.gles3.xml \
-    external/deqp/android/cts/com.drawelements.deqp.gles31.xml
+    $(call cts-get-deqp-test-xmls,$(cts_deqp_test_apis))
 
 # The following files will be placed in the tools directory of the CTS distribution
 CTS_TOOLS_LIST :=
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index 88386ec..460b88a 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -21,6 +21,8 @@
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
+LOCAL_MULTILIB := both
+
 LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
 
 LOCAL_STATIC_JAVA_LIBRARIES := cts-sensors-tests ctstestrunner
@@ -59,17 +61,18 @@
 verifier-zip-name := $(verifier-dir-name).zip
 verifier-zip := $(cts-dir)/$(verifier-zip-name)
 
-$(PRODUCT_OUT)/data/app/CtsVerifier.apk $(verifier-zip): $(verifier-dir)/power/execute_power_tests.py
-$(PRODUCT_OUT)/data/app/CtsVerifier.apk $(verifier-zip): $(verifier-dir)/power/power_monitors/monsoon.py
+# turned off sensor power tests in initial L release
+#$(PRODUCT_OUT)/data/app/CtsVerifier.apk $(verifier-zip): $(verifier-dir)/power/execute_power_tests.py
+#$(PRODUCT_OUT)/data/app/CtsVerifier.apk $(verifier-zip): $(verifier-dir)/power/power_monitors/monsoon.py
 
 # Copy the necessary host-side scripts to include in the zip file:
-$(verifier-dir)/power/power_monitors/monsoon.py: cts/apps/CtsVerifier/assets/scripts/power_monitors/monsoon.py | $(ACP)
-	$(hide) mkdir -p $(verifier-dir)/power/power_monitors
-	$(hide) $(ACP) -fp cts/apps/CtsVerifier/assets/scripts/power_monitors/*.py $(verifier-dir)/power/power_monitors/.
-
-$(verifier-dir)/power/execute_power_tests.py: cts/apps/CtsVerifier/assets/scripts/execute_power_tests.py | $(ACP)
-	$(hide) mkdir -p $(verifier-dir)/power
-	$(hide) $(ACP) -fp cts/apps/CtsVerifier/assets/scripts/execute_power_tests.py $@
+#$(verifier-dir)/power/power_monitors/monsoon.py: cts/apps/CtsVerifier/assets/scripts/power_monitors/monsoon.py | $(ACP)
+#	$(hide) mkdir -p $(verifier-dir)/power/power_monitors
+#	$(hide) $(ACP) -fp cts/apps/CtsVerifier/assets/scripts/power_monitors/*.py $(verifier-dir)/power/power_monitors/.
+#
+#$(verifier-dir)/power/execute_power_tests.py: cts/apps/CtsVerifier/assets/scripts/execute_power_tests.py | $(ACP)
+#	$(hide) mkdir -p $(verifier-dir)/power
+#	$(hide) $(ACP) -fp cts/apps/CtsVerifier/assets/scripts/execute_power_tests.py $@
 
 cts : $(verifier-zip)
 ifeq ($(HOST_OS),linux)
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index c78e1d9..12ed5e5 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -17,8 +17,8 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="com.android.cts.verifier"
-      android:versionCode="3"
-      android:versionName="5.0_r0.5">
+      android:versionCode="4"
+      android:versionName="5.0_r2">
 
     <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="21"/>
 
@@ -48,6 +48,7 @@
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
     <uses-permission android:name="android.permission.READ_CONTACTS"/>
     <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
 
     <!-- Needed by the Audio Quality Verifier to store the sound samples that will be mailed. -->
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@@ -93,6 +94,8 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_device_admin" />
+            <meta-data android:name="test_required_features"
+                    android:value="android.software.device_admin" />
         </activity>
 
         <!-- A generic activity for intent based tests -->
@@ -107,7 +110,7 @@
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_device_admin" />
             <meta-data android:name="test_excluded_features"
-                       android:value="android.hardware.type.television:android.software.leanback" />
+                       android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
         </activity>
 
         <receiver android:name=".admin.TestDeviceAdminReceiver"
@@ -124,6 +127,8 @@
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
+            <meta-data android:name="test_required_features"
+                    android:value="android.software.backup" />
         </activity>
 
         <activity android:name=".bluetooth.BluetoothTestActivity"
@@ -146,6 +151,7 @@
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/bt_control" />
             <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+            <meta-data android:name="test_excluded_features" android:value="android.software.leanback" />
         </activity>
 
         <activity android:name=".bluetooth.SecureServerActivity"
@@ -228,7 +234,8 @@
         <service android:name=".bluetooth.BleScannerService"
                 android:label="@string/ble_scanner_service_name" />
 
-        <activity android:name=".bluetooth.BleClientTestActivity"
+        <!-- TODO: Enable when test quality issues listed in b/18283088 is resolved -->
+        <!-- activity android:name=".bluetooth.BleClientTestActivity"
                 android:label="@string/ble_client_test_name"
                 android:configChanges="keyboardHidden|orientation|screenSize">
             <intent-filter>
@@ -237,7 +244,9 @@
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/bt_le" />
             <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
-        </activity>
+            <meta-data android:name="test_required_features"
+                       android:value="android.hardware.bluetooth_le"/>
+        </activity -->
 
         <activity android:name=".bluetooth.BleClientConnectActivity"
                 android:label="@string/ble_client_connect_name"
@@ -327,7 +336,8 @@
             <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BleClientTestActivity" />
         </activity>
 
-        <activity android:name=".bluetooth.BleServerStartActivity"
+        <!-- TODO: Enable when test quality issues listed in b/18283088 is resolved -->
+        <!-- activity android:name=".bluetooth.BleServerStartActivity"
                 android:label="@string/ble_server_start_name"
                 android:configChanges="keyboardHidden|orientation|screenSize">
             <intent-filter>
@@ -336,9 +346,12 @@
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/bt_le" />
             <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
-        </activity>
+            <meta-data android:name="test_required_features"
+                       android:value="android.hardware.bluetooth_le"/>
+        </activity -->
 
-        <activity android:name=".bluetooth.BleScannerTestActivity"
+        <!-- TODO: Enable when test quality issues listed in b/18282549 is resolved -->
+        <!-- activity android:name=".bluetooth.BleScannerTestActivity"
                 android:label="@string/ble_scanner_test_name"
                 android:configChanges="keyboardHidden|orientation|screenSize">
             <intent-filter>
@@ -347,18 +360,9 @@
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/bt_le" />
             <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
-        </activity>
-
-        <activity android:name=".bluetooth.BleScannerPrivacyMacActivity"
-                android:label="@string/ble_privacy_mac_name"
-                android:configChanges="keyboardHidden|orientation|screenSize">
-            <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/bt_le" />
-            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BleScannerTestActivity" />
-        </activity>
+            <meta-data android:name="test_required_features"
+                       android:value="android.hardware.bluetooth_le"/>
+        </activity -->
 
         <activity android:name=".bluetooth.BleScannerPowerLevelActivity"
                 android:label="@string/ble_power_level_name"
@@ -382,7 +386,8 @@
             <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BleScannerTestActivity" />
         </activity>
 
-        <activity android:name=".bluetooth.BleAdvertiserTestActivity"
+        <!-- TODO: Enable when test quality issues listed in b/18282549 is resolved -->
+        <!-- activity android:name=".bluetooth.BleAdvertiserTestActivity"
                 android:label="@string/ble_advertiser_test_name"
                 android:configChanges="keyboardHidden|orientation|screenSize">
             <intent-filter>
@@ -391,18 +396,9 @@
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/bt_le" />
             <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
-        </activity>
-
-        <activity android:name=".bluetooth.BleAdvertiserPrivacyMacActivity"
-                android:label="@string/ble_privacy_mac_name"
-                android:configChanges="keyboardHidden|orientation|screenSize">
-            <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/bt_le" />
-            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BleAdvertiserTestActivity" />
-        </activity>
+            <meta-data android:name="test_required_features"
+                       android:value="android.hardware.bluetooth_le"/>
+         </activity -->
 
         <activity android:name=".bluetooth.BleAdvertiserPowerLevelActivity"
                 android:label="@string/ble_power_level_name"
@@ -445,7 +441,7 @@
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_security" />
             <meta-data android:name="test_excluded_features"
-                       android:value="android.hardware.type.television:android.software.leanback" />
+                       android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
         </activity>
 
         <activity android:name=".streamquality.StreamingVideoActivity"
@@ -456,6 +452,8 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_streaming" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.watch" />
         </activity>
 
         <activity android:name=".streamquality.PlayVideoActivity"
@@ -800,8 +798,8 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_sensors" />
-            <meta-data android:name="test_required_features"
-                       android:value="android.hardware.sensor.accelerometer" />
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.stepcounter:android.hardware.sensor.stepdetector:android.hardware.sensor.proximity:android.hardware.sensor.light" />
         </activity>
 
         <!-- TODO: enable when a more reliable way to identify time synchronization is available -->
@@ -825,6 +823,8 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST"/>
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_sensors"/>
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.accelerometer:android.hardware.sensor.compass:android.hardware.sensor.gyroscope:android.hardware.sensor.barometer" />
         </activity>
 
         <activity android:name=".sensors.SensorBatchingTestsActivity"
@@ -835,8 +835,8 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST"/>
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_sensors"/>
-            <meta-data android:name="test_excluded_features"
-                       android:value="android.hardware.type.television:android.software.leanback" />
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.accelerometer:android.hardware.sensor.compass:android.hardware.sensor.gyroscope:android.hardware.sensor.barometer" />
         </activity>
 
         <activity android:name=".sensors.SensorIntegrationTestsActivity"
@@ -847,6 +847,8 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST"/>
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_sensors"/>
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.accelerometer:android.hardware.sensor.compass:android.hardware.sensor.gyroscope" />
         </activity>
 
         <activity android:name=".sensors.SensorTestActivity"
@@ -857,6 +859,8 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST"/>
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_sensors"/>
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.accelerometer:android.hardware.sensor.stepcounter:android.hardware.sensor.stepdetector:android.hardware.sensor.heartrate:android.hardware.sensor.compass:android.hardware.sensor.ambient_temperature" />
         </activity>
 
         <!-- End sensor tests definitions -->
@@ -868,6 +872,10 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_location" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.television" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.software.leanback" />
         </activity>
         <activity android:name=".location.LocationModeHighAccuracyTestActivity"
                 android:label="@string/location_mode_high_accuracy_test">
@@ -876,8 +884,12 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_location" />
+            <meta-data android:name="test_required_features"
+                    android:value="android.hardware.location.network:android.hardware.location.gps" />
             <meta-data android:name="test_excluded_features"
-                       android:value="android.hardware.type.television:android.software.leanback" />
+                    android:value="android.hardware.type.television" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.software.leanback" />
         </activity>
         <activity android:name=".location.LocationModeBatterySavingTestActivity"
                 android:label="@string/location_mode_battery_saving_test">
@@ -886,6 +898,11 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_location" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.location.network" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.television" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.software.leanback" />
         </activity>
         <activity android:name=".location.LocationModeDeviceOnlyTestActivity"
                 android:label="@string/location_mode_device_only_test">
@@ -894,8 +911,11 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_location" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.location.gps" />
             <meta-data android:name="test_excluded_features"
-                       android:value="android.hardware.type.television:android.software.leanback" />
+                    android:value="android.hardware.type.television" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.software.leanback" />
         </activity>
 
         <activity android:name=".camera.formats.CameraFormatsActivity"
@@ -997,8 +1017,10 @@
             </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.usb.accessory" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.watch" />
         </activity>
-
+<!-- Turned off Sensor Power Test in initial L release
         <activity android:name=".sensors.SensorPowerTestActivity"
                 android:label="@string/sensor_power_test"
                 android:configChanges="keyboardHidden|orientation|screenSize">
@@ -1010,7 +1032,7 @@
             <meta-data android:name="test_excluded_features"
                        android:value="android.hardware.type.television:android.software.leanback" />
         </activity>
-
+-->
         <activity android:name=".p2p.P2pTestListActivity"
                 android:label="@string/p2p_test"
                 android:configChanges="keyboardHidden|orientation|screenSize">
@@ -1057,6 +1079,12 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_notifications" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.watch" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.television" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.software.leanback" />
         </activity>
         <activity android:name=".security.CANotifyOnBootActivity"
                 android:label="@string/caboot_test">
@@ -1065,6 +1093,12 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_notifications" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.watch" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.television" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.software.leanback" />
         </activity>
 
         <activity android:name=".p2p.GoNegRequesterTestListActivity"
@@ -1112,14 +1146,15 @@
             </intent-filter>
         </activity-alias>
 
-        <activity android:name=".sample.SampleTestActivity"
+        <!-- remove comment from the next activity to see the sample test surfacing in the app -->
+        <!-- activity android:name=".sample.SampleTestActivity"
                   android:label="@string/sample_framework_test">
             <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_other" />
-        </activity>
+        </activity -->
 
         <activity android:name=".widget.WidgetTestActivity"
                 android:label="@string/widget_framework_test">
@@ -1128,6 +1163,10 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_other" />
+            <meta-data android:name="test_required_features"
+                    android:value="android.software.app_widgets" />
+            <meta-data android:name="test_excluded_features"
+                       android:value="android.software.leanback" />
         </activity>
 
         <activity android:name=".deskclock.DeskClockTestsActivity"
@@ -1137,8 +1176,15 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_deskclock" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.television" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.software.leanback" />
         </activity>
 
+<!-- TODO: enable when not requiring to tap the screen and timeouts are tuned -->
+<!-- Removed from initial L release
+
         <activity
                 android:name="com.android.cts.verifier.sensors.StepCounterTestActivity"
                 android:label="@string/snsr_step_counter_test"
@@ -1151,7 +1197,7 @@
             <meta-data android:name="test_excluded_features"
                        android:value="android.hardware.type.television:android.software.leanback" />
         </activity>
-
+-->
         <activity
             android:name="com.android.cts.verifier.sensors.SignificantMotionTestActivity"
             android:label="@string/snsr_significant_motion_test"
@@ -1165,8 +1211,8 @@
             <meta-data
                 android:name="test_category"
                 android:value="@string/test_category_sensors" />
-            <meta-data android:name="test_excluded_features"
-                       android:value="android.hardware.type.television:android.software.leanback" />
+            <meta-data android:name="test_required_features"
+                       android:value="android.hardware.sensor.accelerometer" />
         </activity>
 
         <receiver android:name=".widget.WidgetCtsProvider">
@@ -1190,6 +1236,7 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_projection" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.faketouch" />
         </activity>
 
         <activity android:name=".projection.widgets.ProjectionWidgetActivity"
@@ -1199,6 +1246,7 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_projection" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.faketouch" />
         </activity>
 
         <activity android:name=".projection.list.ProjectionListActivity"
@@ -1208,6 +1256,8 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_projection" />
+            <meta-data android:name="test_excluded_features"
+                       android:value="android.hardware.type.television:android.software.leanback" />
         </activity>
 
         <activity android:name=".projection.video.ProjectionVideoActivity"
@@ -1217,6 +1267,8 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_projection" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.watch" />
         </activity>
 
         <activity android:name=".projection.touch.ProjectionTouchActivity"
@@ -1226,6 +1278,7 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_projection" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.faketouch" />
         </activity>
 
 
@@ -1236,6 +1289,8 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_projection" />
+            <meta-data android:name="test_excluded_features"
+                       android:value="android.hardware.type.television:android.software.leanback" />
         </activity>
 
         <service android:name=".projection.ProjectionService"
@@ -1253,7 +1308,8 @@
         </activity>
 
 
-        <activity android:name=".managedprovisioning.ByodFlowTestActivity"
+        <!-- TODO: enable when the test can be executed without leaving marks -->
+        <!-- activity android:name=".managedprovisioning.ByodFlowTestActivity"
                 android:launchMode="singleTask"
                 android:label="@string/provisioning_byod">
             <intent-filter>
@@ -1266,7 +1322,7 @@
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_managed_provisioning" />
             <meta-data android:name="test_required_features" android:value="android.software.managed_users:android.software.device_admin" />
-        </activity>
+        </activity-->
 
         <activity android:name=".managedprovisioning.ByodHelperActivity">
             <intent-filter>
@@ -1294,6 +1350,45 @@
             </intent-filter>
         </receiver>
 
+        <activity android:name=".jobscheduler.IdleConstraintTestActivity" android:label="@string/js_idle_test">
+            <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_jobscheduler" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.television" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.software.leanback" />
+        </activity>
+
+        <activity android:name=".jobscheduler.ChargingConstraintTestActivity" android:label="@string/js_charging_test">
+            <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_jobscheduler" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.television" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.software.leanback" />
+        </activity>
+
+        <activity android:name=".jobscheduler.ConnectivityConstraintTestActivity" android:label="@string/js_connectivity_test">
+            <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_jobscheduler" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.television" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.software.leanback" />
+        </activity>
+
+        <service android:name=".jobscheduler.MockJobService"
+            android:permission="android.permission.BIND_JOB_SERVICE"/>
+
     </application>
 
 </manifest>
diff --git a/apps/CtsVerifier/res/layout/ble_advertiser_privacy_mac.xml b/apps/CtsVerifier/res/layout/ble_advertiser_privacy_mac.xml
deleted file mode 100644
index 1c68b98..0000000
--- a/apps/CtsVerifier/res/layout/ble_advertiser_privacy_mac.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        android:padding="10dip"
-        >
-    <TextView android:text="@string/ble_advertiser_privacy_mac_instruction"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-    />
-    <LinearLayout android:orientation="horizontal"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_centerInParent="true"
-            >
-        <Button android:id="@+id/ble_privacy_mac_start"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/ble_advertiser_start"
-                />
-        <Button android:id="@+id/ble_privacy_mac_stop"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/ble_advertiser_stop"
-                />
-    </LinearLayout>
-
-    <include android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_alignParentBottom="true"
-            layout="@layout/pass_fail_buttons"
-            />
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/ble_scanner_power_level.xml b/apps/CtsVerifier/res/layout/ble_scanner_power_level.xml
index 970b03a..b240db6 100644
--- a/apps/CtsVerifier/res/layout/ble_scanner_power_level.xml
+++ b/apps/CtsVerifier/res/layout/ble_scanner_power_level.xml
@@ -22,11 +22,14 @@
     <TextView android:text="@string/ble_scanner_power_level_instruction"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:id="@+id/ble_scanner_power_level_instruction"
     />
     <LinearLayout android:orientation="vertical"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:layout_below="@+id/ble_scanner_power_level_instruction"
             android:layout_centerInParent="true"
+            android:padding="10dp"
             >
         <LinearLayout android:orientation="horizontal"
                 android:layout_width="match_parent"
@@ -156,6 +159,9 @@
                     android:layout_height="wrap_content"
             />
         </LinearLayout>
+        <TextView android:id="@+id/ble_timer"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content" />
     </LinearLayout>
 
     <include android:layout_width="match_parent"
diff --git a/apps/CtsVerifier/res/layout/ble_scanner_privacy_mac.xml b/apps/CtsVerifier/res/layout/ble_scanner_privacy_mac.xml
deleted file mode 100644
index cad78a3..0000000
--- a/apps/CtsVerifier/res/layout/ble_scanner_privacy_mac.xml
+++ /dev/null
@@ -1,80 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical"
-        android:padding="10dip"
-        >
-
-    <TextView
-            android:text="@string/ble_scanner_privacy_mac_instruction"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-    />
-    <LinearLayout android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_centerInParent="true"
-            >
-        <LinearLayout android:orientation="horizontal"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_centerInParent="true"
-                >
-            <TextView android:text="@string/ble_address"
-                  android:layout_width="100dp"
-                  android:layout_height="wrap_content"
-            />
-            <TextView android:id="@+id/ble_mac_address"
-                  android:layout_weight="1"
-                  android:layout_width="0dp"
-                  android:layout_height="wrap_content"
-            />
-        </LinearLayout>
-        <LinearLayout android:orientation="horizontal"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_centerInParent="true"
-                >
-            <TextView android:id="@+id/ble_mac_count"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-            />
-            <TextView android:id="@+id/ble_resp_count"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_below="@+id/ble_mac_count"
-            />
-        </LinearLayout>
-        <LinearLayout android:orientation="horizontal"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_centerInParent="true"
-                >
-            <TextView android:id="@+id/ble_timer"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-            />
-        </LinearLayout>
-    </LinearLayout>
-
-    <include android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_alignParentBottom="true"
-            layout="@layout/pass_fail_buttons"
-            />
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/js_charging.xml b/apps/CtsVerifier/res/layout/js_charging.xml
new file mode 100644
index 0000000..4c0e552
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/js_charging.xml
@@ -0,0 +1,67 @@
+<?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">
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/js_test_description"
+        android:layout_margin="@dimen/js_padding"/>
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="@dimen/js_padding"
+        android:text="@string/js_charging_description_1"
+        android:textStyle="bold"/>
+    <Button
+        android:id="@+id/js_charging_start_test_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:text="@string/js_start_test_text"
+        android:onClick="startTest"
+        android:enabled="false"/>
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/js_padding"
+        android:layout_marginBottom="@dimen/js_padding">
+        <ImageView
+            android:id="@+id/charging_off_test_image"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/fs_indeterminate"
+            android:layout_marginRight="@dimen/js_padding"/>
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/js_charging_off_test"
+            android:textSize="16dp"/>
+    </LinearLayout>
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="@dimen/js_padding"
+        android:text="@string/js_charging_description_2"
+        android:textStyle="bold"/>
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/js_padding"
+        android:layout_marginBottom="@dimen/js_padding">
+        <ImageView
+            android:id="@+id/charging_on_test_image"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/fs_indeterminate"
+            android:layout_marginRight="@dimen/js_padding"/>
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/js_charging_on_test"
+            android:textSize="16dp"/>
+    </LinearLayout>
+    <include layout="@layout/pass_fail_buttons" />
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/js_connectivity.xml b/apps/CtsVerifier/res/layout/js_connectivity.xml
new file mode 100644
index 0000000..5208c18
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/js_connectivity.xml
@@ -0,0 +1,83 @@
+<?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">
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/js_test_description"
+        android:layout_margin="@dimen/js_padding"/>
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/js_connectivity_description_1"
+        android:layout_margin="@dimen/js_padding"
+        android:textStyle="bold"/>
+
+    <Button
+        android:id="@+id/js_connectivity_start_test_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:text="@string/js_start_test_text"
+        android:onClick="startTest"
+        android:enabled="false"/>
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/js_padding"
+        android:layout_marginBottom="@dimen/js_padding">
+        <ImageView
+            android:id="@+id/connectivity_off_test_unmetered_image"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/fs_indeterminate"
+            android:layout_marginRight="@dimen/js_padding"/>
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/js_unmetered_connectivity_test"
+            android:textSize="16dp"/>
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/js_padding"
+        android:layout_marginBottom="@dimen/js_padding">
+        <ImageView
+            android:id="@+id/connectivity_off_test_any_connectivity_image"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/fs_indeterminate"
+            android:layout_marginRight="@dimen/js_padding"/>
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/js_any_connectivity_test"
+            android:textSize="16dp"/>
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/js_padding"
+        android:layout_marginBottom="@dimen/js_padding">
+        <ImageView
+            android:id="@+id/connectivity_off_test_no_connectivity_image"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/fs_indeterminate"
+            android:layout_marginRight="@dimen/js_padding"/>
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/js_no_connectivity_test"
+            android:textSize="16dp"/>
+    </LinearLayout>
+
+    <include layout="@layout/pass_fail_buttons" />
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/js_idle.xml b/apps/CtsVerifier/res/layout/js_idle.xml
new file mode 100644
index 0000000..90e55ec
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/js_idle.xml
@@ -0,0 +1,63 @@
+<?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">
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/js_test_description"
+        android:layout_margin="@dimen/js_padding"/>
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/js_idle_description_1"
+        android:layout_margin="@dimen/js_padding"
+        android:textStyle="bold"/>
+
+    <Button
+        android:id="@+id/js_idle_start_test_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:text="@string/js_start_test_text"
+        android:onClick="startTest"
+        android:enabled="false"/>
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/js_padding"
+        android:layout_marginBottom="@dimen/js_padding">
+        <ImageView
+            android:id="@+id/idle_off_test_image"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/fs_indeterminate"
+            android:layout_marginRight="@dimen/js_padding"/>
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/js_idle_item_idle_off"
+            android:textSize="16dp"/>
+    </LinearLayout>
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/js_padding"
+        android:layout_marginBottom="@dimen/js_padding">
+        <ImageView
+            android:id="@+id/idle_on_test_image"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/fs_indeterminate"
+            android:layout_marginRight="@dimen/js_padding"/>
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/js_idle_item_idle_on"
+            android:textSize="16dp"/>
+    </LinearLayout>
+    <include layout="@layout/pass_fail_buttons" />
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/pa_main.xml b/apps/CtsVerifier/res/layout/pa_main.xml
index b6b8e4b..76cb7d4 100644
--- a/apps/CtsVerifier/res/layout/pa_main.xml
+++ b/apps/CtsVerifier/res/layout/pa_main.xml
@@ -17,11 +17,15 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent" >
 
+    <include
+        android:id="@+id/pass_fail_buttons"
+        android:layout_gravity="top"
+        layout="@layout/pass_fail_buttons" />
+
     <TextureView
         android:id="@+id/texture_view"
         android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
-     <include layout="@layout/pass_fail_buttons" />
+        android:layout_height="match_parent"
+        android:layout_below="@id/pass_fail_buttons" />
 
 </RelativeLayout>
diff --git a/apps/CtsVerifier/res/values-television/strings.xml b/apps/CtsVerifier/res/values-television/strings.xml
new file mode 100644
index 0000000..1042fa8
--- /dev/null
+++ b/apps/CtsVerifier/res/values-television/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<resources>
+    <!-- Don't test these features on televisions. -->
+    <string-array name="disabled_tests">
+        <item>com.android.cts.verifier.notifications.NotificationAttentionManagementVerifierActivity</item>
+        <item>com.android.cts.verifier.notifications.NotificationListenerVerifierActivity</item>
+    </string-array>
+</resources>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/values-watch/strings.xml b/apps/CtsVerifier/res/values-watch/strings.xml
new file mode 100644
index 0000000..1f25b04
--- /dev/null
+++ b/apps/CtsVerifier/res/values-watch/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<resources>
+    <!-- Don't test these features on watches. -->
+    <string-array name="disabled_tests">
+        <item>com.android.cts.verifier.notifications.NotificationAttentionManagementVerifierActivity</item>
+        <item>com.android.cts.verifier.notifications.NotificationListenerVerifierActivity</item>
+    </string-array>
+</resources>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/values/dimens.xml b/apps/CtsVerifier/res/values/dimens.xml
index b1367f7..8df5b35 100644
--- a/apps/CtsVerifier/res/values/dimens.xml
+++ b/apps/CtsVerifier/res/values/dimens.xml
@@ -36,4 +36,6 @@
     <dimen name="snsr_view_padding_left">8dp</dimen>
     <dimen name="snsr_view_padding_right">8dp</dimen>
 
+    <dimen name="js_padding">10dp</dimen>
+
 </resources>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 22e0cff..3225bcf 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -35,6 +35,7 @@
     <string name="test_category_streaming">Streaming</string>
     <string name="test_category_features">Features</string>
     <string name="test_category_deskclock">Clock</string>
+    <string name="test_category_jobscheduler">Job Scheduler</string>
     <string name="test_category_other">Other</string>
     <string name="clear">Clear</string>
     <string name="test_results_cleared">Test results cleared.</string>
@@ -66,7 +67,10 @@
         \n\nFollow the instructions below to check that the data backup and restore works:
         \n\n1. Make sure backup and automatic restore are enabled in settings. Depending on the
         backup transport supported by the device you may need to do additional steps. For instance
-        you may need to set a Google account as the backup account for the device.
+        you may need to set a Google account as the backup account for the device. If you cannot
+        find the corresponding setting options on your device, run \"adb shell bmgr enable true\"
+        to enable the backup manager. You can check its status by executing \"adb shell bmgr
+        enabled\".
         \n\n2. Run the backup manager: adb shell bmgr run
         \n\n3. Uninstall the program: adb uninstall com.android.cts.verifier
         \n\n4. Reinstall the CTS Verifier and verify that the values are still the same.
@@ -238,7 +242,7 @@
     <string name="ble_power_level_info">BLE Advertiser advertises in 4 different power levels. Scanner should receive them in different strength of Rssi, cannot receive weak signals beyond several feet.</string>
     <string name="ble_advertiser_power_level_instruction">Click start to start multi-advertising. Data packets are advertised in 4 different power levels. You may receive message that this device does not support multi advertising. If advertiser does not advertise in 4 power levels, neither you receive the error message, you may not stop the advertising in previous test, or this device does not support 4 advertisers at the same time. Try rebooting the device and run the test to free those advertisers in use.</string>
     <string name="ble_advertiser_scan_filter_name">BLE Hardware Scan Filter</string>
-    <string name="ble_advertiser_scan_filter_info">BLE Advertiser advertises with 2 different data separately. One can wake up the scanner, the other cannot.</string>
+    <string name="ble_advertiser_scan_filter_info">BLE Advertiser advertises with 2 different data separately. One can wake up the scanner, the other cannot. This test cares about behavior on scanner only.</string>
     <string name="ble_advertiser_scannable">Scannable advertising</string>
     <string name="ble_advertiser_scannable_instruction">Start scannable advertising, expect scanner consume more power on Monsoon monitor, or see log of GattService from scanner logcat.</string>
     <string name="ble_advertiser_unscannable">Unscannble advertising</string>
@@ -256,10 +260,10 @@
     <string name="ble_low">Low</string>
     <string name="ble_medium">Medium</string>
     <string name="ble_high">High</string>
-    <string name="ble_scanner_power_level_instruction">Count: Ultra low &lt; low &lt; medium &lt; high\nRssi: Ultra low &lt; low &lt; medium &lt; high\nDistance to see count freezing: Ultra low &lt; low &lt; medium &lt; high\nA common error is ultra low, low and medium behave similarly, with similar rssi, freeze at similar distance.</string>
+    <string name="ble_scanner_power_level_instruction">Count: Ultra low &lt; low &lt; medium &lt; high\nRssi: Ultra low &lt; low &lt; medium &lt; high\nDistance to see count freezing: Ultra low &lt; low &lt; medium &lt; high\nA common error is ultra low, low and medium behave similarly, with similar rssi, freeze at similar distance.\n\n All power level receive a different mac address. After 15 mins, a green text "Get a new Mac address" will show up.</string>
     <string name="ble_scanner_scan_filter_name">BLE Hardware Scan Filter</string>
     <string name="ble_scanner_scan_filter_info">Lock the screen of scanner, and connect to monsoon. It will not wake up when advertiser is advertising unscannable, and scanner is scanning with filter.</string>
-    <string name="ble_scanner_scan_filter_instruction">For monsoon test:\n\tClick scan with filter, lock the screen, connect to monsoon. It will not wake up when advertiser is advertising unscannable data packets, but will show a peak in power usage when advertiser is advertising scannable data.\nFor logcat test:\n\tClick scan with filter, logcat the scanner. No data will be received by GattService when advertiser is advertising unscannable data.</string>
+    <string name="ble_scanner_scan_filter_instruction">Scan filter is to scan data with service UUID = 0x6666 only. If you scan without scan filter, data with service UUID = 0x5555 and 0x6666 will show up on screen.\nFor monsoon test:\n\tClick scan with filter, lock the screen, connect to monsoon. It will not wake up when advertiser is advertising unscannable data packets, but will show a peak in power usage when advertiser is advertising scannable data.\nFor logcat test:\n\tClick scan with filter, logcat the scanner. No data will be received by GattService when advertiser is advertising unscannable data.</string>
     <string name="ble_scan_with_filter">Scan with filter</string>
     <string name="ble_scan_without_filter">Scan without filter</string>
 
@@ -469,7 +473,7 @@
     <string name="snsr_test_pass">PASS</string>
     <string name="snsr_test_skipped">SKIPPED</string>
     <string name="snsr_test_fail">FAIL</string>
-    <string name="snsr_executing_test">\nExecuting test case \'%1$s\'..\n</string>
+    <string name="snsr_execution_time">Test execution time %1$s sec</string>
 
     <!-- Strings to interact with users in Sensor Tests -->
     <string name="snsr_test_play_sound">A sound will be played once the verification is complete...</string>
@@ -479,10 +483,10 @@
     <string name="snsr_keep_device_rotating_clockwise">Once the test begins, you will have to keep rotating the device clockwise.</string>
     <string name="snsr_wait_for_user">Press \'Next\' to continue.</string>
     <string name="snsr_wait_to_begin">Press \'Next\' to begin.</string>
-    <string name="snsr_wait_to_complete">Press \'Next\' to complete.</string>
     <string name="snsr_on_complete_return">After completing the task, go back to this test.</string>
     <string name="snsr_movement_expected">Movement was expected during the test. Found=%1$b.</string>
-    <string name="snsr_sensor_feature_deactivation">Additionally, turn off any other features installed in the device, that register for sensors. Once you are done, you can continue the test.</string>
+    <string name="snsr_sensor_feature_deactivation">Turn off any special features installed in the
+        device that register for sensors. Once you are done, you can begin the test.</string>
     <string name="snsr_setting_mode_request">You will be redirected to set \'%1$s\' to: %2$s.</string>
     <string name="snsr_setting_mode_set">\'%1$s\' set to: %2$s.</string>
     <string name="snsr_setting_mode_not_set">\'%1$s\' not set to: %2$s.</string>
@@ -491,7 +495,7 @@
     <string name="snsr_setting_auto_rotate_screen_mode">Auto-rotate screen</string>
     <string name="snsr_setting_keep_screen_on">Stay awake</string>
     <string name="snsr_setting_location_mode">Location</string>
-    <string name="snsr_setting_auto_screen_off_mode">Display Sleep</string>
+    <string name="snsr_setting_ambient_display">Ambient Display</string>
     <string name="snsr_pass_on_error">Pass Anyway</string>
     <string name="snsr_run_automated_tests">The screen will be turned off to execute the tests,
         when tests complete, the device will vibrate and the screen will be turned back on.</string>
@@ -526,7 +530,6 @@
         facing the ceiling. Read the instructions for each scenario, before you perform the
         test.</string>
     <string name="snsr_gyro_device_static">Leave the device static.</string>
-    <string name="snsr_gyro_rotate_clockwise">Rotate the device clockwise.</string>
     <string name="snsr_gyro_rotate_device">Once you begin the test, you will need to rotate the
         device 360deg (one time) in the direction show by the animation, then place it back on the
         flat surface.</string>
@@ -550,20 +553,15 @@
     <string name="snsr_mag_measurement">-&gt; (%1$.2f, %2$.2f, %3$.2f) : %4$.2f uT</string>
 
     <!-- Sensor Value Accuracy -->
-    <string name="snsr_val_acc_test">Sensor Value Accuracy Tests</string>
     <string name="snsr_rot_vec_test">Rotation Vector Accuracy Test</string>
-    <string name="snsr_collected_events_length">Sensor(%2$s). Collected events expected to be greater than zero. Found=%1$d.</string>
     <string name="snsr_event_length">Sensor(%3$s). Event values expected to have size=%1$d. Found=%2$d.</string>
-    <string name="snsr_event_length_positive">Sensor(%2$s). Event values expected to have size > 0. Found=%1$d</string>
     <string name="snsr_event_value">Sensor(%3$s). Event value[0] expected to be of value=%1$f. Found=%2$f.</string>
     <string name="snsr_event_time">Sensor(%5$s). Event timestamp expected to be synchronized with SystemClock.elapsedRealtimeNanos(). Event received at=%1$d. Event timestamp=%2$d. Delta=%3$d. Threshold=%4$d.</string>
-    <string name="snsr_event_time_positive">Sensor(%2$s). Event timestamp expected to positive (> 0). Found=%1$d.</string>
 
     <!-- Sensor Batching -->
     <string name="snsr_batch_test">Sensor Batching Tests</string>
     <string name="snsr_batching_walking_needed">Once the test begins, you will have to take the
         device in your hand and walk.</string>
-    <string name="snsr_batching_fifo_count">FifoReservedEventCount=%1$d. Expected to be at most FifoMaxEventCount=%2$d.</string>
 
     <!-- Sensor Synchronization -->
     <string name="snsr_synch_test">Sensor Synchronization Test</string>
@@ -1159,7 +1157,7 @@
     <string name="pwa_info">This tests whether or displaying widets and keyfocus navigation works.\n
         You should see four buttons on the bottom of the screen.\n
         Pressing the "up" and "down" buttons should highlight different buttons.\n
-        Further, you should also be able to touch them and they should highlight as ususual.</string>
+        Further, you should also be able to touch them and they should highlight as usual.</string>
     <string name="pwa_test">Projection Widget Test</string>
     <string name="pwa_button_up">Up</string>
     <string name="pwa_button_down">Down</string>
@@ -1269,6 +1267,34 @@
     <string name="device_owner_provisioning_tests_info">The device owner provisioning tests verify that setting up a corporate owned device can only be done on a factory reset device.</string>
     <string name="device_owner_provisioning_category">Device Owner Provisioning</string>
     <string name="device_owner_negative_test">Device owner negative test</string>
-    <string name="device_owner_negative_test_info">Device owner provisioning should only work on new or factory reset devices. Please click on the "Start provisioning" button and verify that you get a warning dialog telling you that the device is already set up. If that is the case, this test has passed.</string>
+    <string name="device_owner_negative_test_info">Please click the "Start provisioning" button, and when you see a warning dialog telling the device is already set up, select "pass". Otherwise, select "fail".</string>
     <string name="start_device_owner_provisioning_button">Start provisioning</string>
+
+    <!-- Strings for JobScheduler Tests -->
+    <string name="js_test_description">This test is mostly automated, but requires some user interaction. You can pass this test once the list items below are checked.</string>
+
+    <string name="js_idle_test">Idle Mode Constraints</string>
+    <string name="js_start_test_text">Start test</string>
+    <string name="js_idle_instructions">Verify the behaviour of the JobScheduler API for when the device is in idle mode. Simply follow the on-screen instructions.</string>
+    <string name="js_idle_description_1">Turn the screen off and then back on in order to begin.</string>
+    <string name="js_idle_item_idle_off">Idle job does not execute when device is not idle.</string>
+    <string name="js_idle_item_idle_on">Idle job does execute when device is forced into idle.</string>
+
+    <string name="js_charging_test">Charging Constraints</string>
+    <string name="js_charging_instructions">Verify the behaviour of the JobScheduler API for when the device is on power and unplugged from power. Simply follow the on-screen instructions.</string>
+    <string name="js_charging_description_1">Unplug the phone in order to begin.</string>
+    <string name="js_charging_off_test">Device not charging will not execute a job with a charging constraint.</string>
+    <string name="js_charging_on_test">Device when charging will execute a job with a charging constraint.</string>
+    <string name="js_charging_description_2">After the above test has passed, plug the device back in to continue. If the above failed, you can simply fail this test.</string>
+
+    <string name="js_connectivity_test">Connectivity Constraints</string>
+    <string name="js_connectivity_instructions">Verify the behaviour of the JobScheduler API for when the device has no access to data connectivity. Simply follow the on-screen instructions.</string>
+    <string name="js_connectivity_description_1">Disable WiFi and Cellular data to begin.</string>
+    <string name="js_unmetered_connectivity_test">Device with no connectivity will not execute a job with an unmetered connectivity constraint.</string>
+    <string name="js_any_connectivity_test">Device with no connectivity will not execute a job with an unmetered connectivity constraint.</string>
+    <string name="js_no_connectivity_test">Device with no connectivity will still execute a job with no connectivity constraints.</string>
+
+    <!-- A list of fully-qualified test classes that should not be run. -->
+    <string-array name="disabled_tests" />
+
 </resources>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java b/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
index 2f42e81..ebddf4f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
@@ -22,12 +22,14 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Bundle;
+import android.util.Log;
 import android.widget.ListView;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -75,6 +77,13 @@
  *             <meta-data android:name="test_excluded_features" android:value="android.hardware.type.television" />
  *         </pre>
  *     </li>
+ *     <li>OPTIONAL: Add a meta data attribute to indicate features such that, if any present,
+ *         the test is applicable to run. If the device has any of the applicable features then
+ *         the test will appear in the test list. Use a colon (:) to specify multiple features
+ *         <pre>
+ *             <meta-data android:name="test_applicable_features" android:value="android.hardware.sensor.compass" />
+ *         </pre>
+ *     </li>
  *
  * </ol>
  */
@@ -88,6 +97,10 @@
 
     private static final String TEST_EXCLUDED_FEATURES_META_DATA = "test_excluded_features";
 
+    private static final String TEST_APPLICABLE_FEATURES_META_DATA = "test_applicable_features";
+
+    private final HashSet<String> mDisabledTests;
+
     private Context mContext;
 
     private String mTestParent;
@@ -96,6 +109,12 @@
         super(context);
         mContext = context;
         mTestParent = testParent;
+
+        String[] disabledTestArray = context.getResources().getStringArray(R.array.disabled_tests);
+        mDisabledTests = new HashSet<>(disabledTestArray.length);
+        for (int i = 0; i < disabledTestArray.length; i++) {
+            mDisabledTests.add(disabledTestArray[i]);
+        }
     }
 
     @Override
@@ -158,13 +177,18 @@
         int size = list.size();
         for (int i = 0; i < size; i++) {
             ResolveInfo info = list.get(i);
+            if (info.activityInfo == null || mDisabledTests.contains(info.activityInfo.name)) {
+                Log.w("CtsVerifier", "ignoring disabled test: " + info.activityInfo.name);
+                continue;
+            }
             String title = getTitle(mContext, info.activityInfo);
             String testName = info.activityInfo.name;
             Intent intent = getActivityIntent(info.activityInfo);
             String[] requiredFeatures = getRequiredFeatures(info.activityInfo.metaData);
             String[] excludedFeatures = getExcludedFeatures(info.activityInfo.metaData);
-            TestListItem item = TestListItem.newTest(title, testName, intent,
-                                                     requiredFeatures, excludedFeatures);
+            String[] applicableFeatures = getApplicableFeatures(info.activityInfo.metaData);
+            TestListItem item = TestListItem.newTest(title, testName, intent, requiredFeatures,
+                    excludedFeatures, applicableFeatures);
 
             String testCategory = getTestCategory(mContext, info.activityInfo.metaData);
             addTestToCategory(testsByCategory, testCategory, item);
@@ -215,6 +239,19 @@
         }
     }
 
+    static String[] getApplicableFeatures(Bundle metaData) {
+        if (metaData == null) {
+            return null;
+        } else {
+            String value = metaData.getString(TEST_APPLICABLE_FEATURES_META_DATA);
+            if (value == null) {
+                return null;
+            } else {
+                return value.split(":");
+            }
+        }
+    }
+
     static String getTitle(Context context, ActivityInfo activityInfo) {
         if (activityInfo.labelRes != 0) {
             return context.getString(activityInfo.labelRes);
@@ -268,10 +305,10 @@
     List<TestListItem> filterTests(List<TestListItem> tests) {
         List<TestListItem> filteredTests = new ArrayList<TestListItem>();
         for (TestListItem test : tests) {
-            String[] excludedFeatures = test.excludedFeatures;
-            String[] requiredFeatures = test.requiredFeatures;
-            if (!hasAnyFeature(excludedFeatures) && hasAllFeatures(requiredFeatures)) {
-                filteredTests.add(test);
+            if (!hasAnyFeature(test.excludedFeatures) && hasAllFeatures(test.requiredFeatures)) {
+                if (test.applicableFeatures == null || hasAnyFeature(test.applicableFeatures)) {
+                    filteredTests.add(test);
+                }
             }
         }
         return filteredTests;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java
index 0d9985c..afe3a73 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java
@@ -86,26 +86,43 @@
         /** Features such that, if any present, the test gets excluded from being shown. */
         final String[] excludedFeatures;
 
+        /** If any of of the features are present the test is meaningful to run. */
+        final String[] applicableFeatures;
+
+        public static TestListItem newTest(Context context, int titleResId, String testName,
+                Intent intent, String[] requiredFeatures, String[] excludedFeatures,
+                String[] applicableFeatures) {
+            return newTest(context.getString(titleResId), testName, intent, requiredFeatures,
+                    excludedFeatures, applicableFeatures);
+        }
+
         public static TestListItem newTest(Context context, int titleResId, String testName,
                 Intent intent, String[] requiredFeatures, String[] excludedFeatures) {
-            return newTest(context.getString(titleResId), testName, intent,
-                           requiredFeatures, excludedFeatures);
+            return newTest(context.getString(titleResId), testName, intent, requiredFeatures,
+                    excludedFeatures, null);
         }
 
         public static TestListItem newTest(Context context, int titleResId, String testName,
                 Intent intent, String[] requiredFeatures) {
-            return newTest(context.getString(titleResId), testName, intent,
-                           requiredFeatures, null);
+            return newTest(context.getString(titleResId), testName, intent, requiredFeatures, null,
+                    null);
+        }
+
+        public static TestListItem newTest(String title, String testName, Intent intent,
+                String[] requiredFeatures, String[] excludedFeatures, String[] applicableFeatures) {
+            return new TestListItem(title, testName, intent, requiredFeatures, excludedFeatures,
+                    applicableFeatures);
         }
 
         public static TestListItem newTest(String title, String testName, Intent intent,
                 String[] requiredFeatures, String[] excludedFeatures) {
-            return new TestListItem(title, testName, intent, requiredFeatures, excludedFeatures);
+            return new TestListItem(title, testName, intent, requiredFeatures, excludedFeatures,
+                    null);
         }
 
         public static TestListItem newTest(String title, String testName, Intent intent,
                 String[] requiredFeatures) {
-            return new TestListItem(title, testName, intent, requiredFeatures, null);
+            return new TestListItem(title, testName, intent, requiredFeatures, null, null);
         }
 
         public static TestListItem newCategory(Context context, int titleResId) {
@@ -113,16 +130,17 @@
         }
 
         public static TestListItem newCategory(String title) {
-            return new TestListItem(title, null, null, null, null);
+            return new TestListItem(title, null, null, null, null, null);
         }
 
         private TestListItem(String title, String testName, Intent intent,
-                String[] requiredFeatures, String[] excludedFeatures) {
+                String[] requiredFeatures, String[] excludedFeatures, String[] applicableFeatures) {
             this.title = title;
             this.testName = testName;
             this.intent = intent;
             this.requiredFeatures = requiredFeatures;
             this.excludedFeatures = excludedFeatures;
+            this.applicableFeatures = applicableFeatures;
         }
 
         boolean isTest() {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserHardwareScanFilterActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserHardwareScanFilterActivity.java
index 242bb08..be2fef9 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserHardwareScanFilterActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserHardwareScanFilterActivity.java
@@ -83,6 +83,7 @@
     public void onResume() {
         super.onResume();
         IntentFilter filter = new IntentFilter();
+        filter.addAction(BleAdvertiserService.BLE_ADV_NOT_SUPPORT);
         filter.addAction(BleAdvertiserService.BLE_START_SCANNABLE);
         filter.addAction(BleAdvertiserService.BLE_START_UNSCANNABLE);
         filter.addAction(BleAdvertiserService.BLE_STOP_SCANNABLE);
@@ -106,6 +107,10 @@
         Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
     }
 
+    private void pass() {
+        this.setTestResultAndFinish(true);
+    }
+
     private void stopAdvertising() {
         Intent intent = new Intent(BleAdvertiserHardwareScanFilterActivity.this,
                                    BleAdvertiserService.class);
@@ -130,6 +135,9 @@
                 case BleAdvertiserService.BLE_STOP_UNSCANNABLE:
                     showMessage("Stop advertising");
                     break;
+                case BleAdvertiserService.BLE_ADV_NOT_SUPPORT:
+                    pass();
+                    break;
             }
         }
     };
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserPowerLevelActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserPowerLevelActivity.java
index 3568002..1cc9206 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserPowerLevelActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserPowerLevelActivity.java
@@ -67,6 +67,7 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(BleAdvertiserService.BLE_START_POWER_LEVEL);
         filter.addAction(BleAdvertiserService.BLE_STOP_POWER_LEVEL);
+        filter.addAction(BleAdvertiserService.BLE_ADV_NOT_SUPPORT);
         registerReceiver(onBroadcast, filter);
     }
 
@@ -94,6 +95,10 @@
         Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
     }
 
+    private void pass() {
+        this.setTestResultAndFinish(true);
+    }
+
     private BroadcastReceiver onBroadcast = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -104,6 +109,9 @@
                 case BleAdvertiserService.BLE_STOP_POWER_LEVEL:
                     showMessage("Stop advertising");
                     break;
+                case BleAdvertiserService.BLE_ADV_NOT_SUPPORT:
+                    pass();
+                    break;
             }
         }
     };
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserPrivacyMacActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserPrivacyMacActivity.java
deleted file mode 100644
index 87879bd..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserPrivacyMacActivity.java
+++ /dev/null
@@ -1,111 +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 com.android.cts.verifier.bluetooth;
-
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.Toast;
-
-public class BleAdvertiserPrivacyMacActivity extends PassFailButtons.Activity {
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.ble_advertiser_privacy_mac);
-        setPassFailButtonClickListeners();
-        setInfoResources(R.string.ble_privacy_mac_name,
-                         R.string.ble_privacy_mac_info, -1);
-
-        ((Button) findViewById(R.id.ble_privacy_mac_start))
-            .setOnClickListener(new OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    Intent intent = new Intent(BleAdvertiserPrivacyMacActivity.this,
-                                               BleAdvertiserService.class);
-                    intent.putExtra(BleAdvertiserService.EXTRA_COMMAND,
-                                    BleAdvertiserService.COMMAND_START_ADVERTISE);
-                    startService(intent);
-                }
-            });
-        ((Button) findViewById(R.id.ble_privacy_mac_stop))
-            .setOnClickListener(new OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    stopAdvertising();
-                }
-            });
-
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(BleAdvertiserService.BLE_START_ADVERTISE);
-        filter.addAction(BleAdvertiserService.BLE_STOP_ADVERTISE);
-        registerReceiver(onBroadcast, filter);
-    }
-
-    @Override
-    public void onPause() {
-        super.onPause();
-        unregisterReceiver(onBroadcast);
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        stopAdvertising();
-    }
-
-    private void showMessage(String msg) {
-        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
-    }
-
-    private void stopAdvertising() {
-        Intent intent = new Intent(BleAdvertiserPrivacyMacActivity.this,
-                                   BleAdvertiserService.class);
-        intent.putExtra(BleAdvertiserService.EXTRA_COMMAND,
-                        BleAdvertiserService.COMMAND_STOP_ADVERTISE);
-        startService(intent);
-    }
-
-    private BroadcastReceiver onBroadcast = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            switch (intent.getAction()) {
-                case BleAdvertiserService.BLE_START_ADVERTISE:
-                    showMessage("Start advertising, please hold for 15 min");
-                    break;
-                case BleAdvertiserService.BLE_STOP_ADVERTISE:
-                    showMessage("Stop advertising");
-                    break;
-            }
-        }
-    };
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserService.java
index 7b4235b..281b2e8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertiserService.java
@@ -53,6 +53,8 @@
     public static final int COMMAND_START_UNSCANNABLE = 6;
     public static final int COMMAND_STOP_UNSCANNABLE = 7;
 
+    public static final String BLE_ADV_NOT_SUPPORT =
+            "com.android.cts.verifier.bluetooth.BLE_ADV_NOT_SUPPORT";
     public static final String BLE_START_ADVERTISE =
             "com.android.cts.verifier.bluetooth.BLE_START_ADVERTISE";
     public static final String BLE_STOP_ADVERTISE =
@@ -147,11 +149,15 @@
     public void onDestroy() {
         super.onDestroy();
         if (mAdvertiser != null) {
-            mAdvertiser.stopAdvertising(mCallback);
+            stopAdvertiser();
         }
     }
 
     private void stopAdvertiser() {
+        if (mAdvertiser == null) {
+            mAdvertiserStatus = 0;
+            return;
+        }
         if ((mAdvertiserStatus & (1 << COMMAND_START_ADVERTISE)) > 0) {
             mAdvertiser.stopAdvertising(mCallback);
         }
@@ -186,8 +192,12 @@
     }
 
     private void handleIntent(Intent intent) {
-        if (mAdvertiser == null) {
-            showMessage("Multi advertising not supported on this device");
+        if (mBluetoothAdapter != null && !mBluetoothAdapter.isMultipleAdvertisementSupported()) {
+            showMessage("Multiple advertisement is not supported.");
+            sendBroadcast(new Intent(BLE_ADV_NOT_SUPPORT));
+            return;
+        } else if (mAdvertiser == null) {
+            showMessage("Cannot start advertising on this device.");
             return;
         }
         int command = intent.getIntExtra(EXTRA_COMMAND, -1);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientConnectActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientConnectActivity.java
old mode 100644
new mode 100755
index a3a9830..fb351b1
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientConnectActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientConnectActivity.java
@@ -63,19 +63,15 @@
                 }
             }
         });
-    }
 
-    @Override
-    public void onResume() {
-        super.onResume();
         IntentFilter filter = new IntentFilter();
         filter.addAction(BleClientService.BLE_BLUETOOTH_CONNECTED);
         registerReceiver(onBroadcast, filter);
     }
 
     @Override
-    public void onPause() {
-        super.onPause();
+    protected void onDestroy(){
+        super.onDestroy();
         unregisterReceiver(onBroadcast);
     }
 
@@ -90,4 +86,4 @@
             getPassButton().setEnabled(true);
         }
     };
-}
\ No newline at end of file
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerPowerLevelActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerPowerLevelActivity.java
index 925c766..a6489c1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerPowerLevelActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerPowerLevelActivity.java
@@ -19,6 +19,7 @@
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
 
+import java.lang.Math;
 import java.util.Set;
 import java.util.Map;
 import java.util.HashMap;
@@ -29,6 +30,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Bundle;
+import android.os.CountDownTimer;
 import android.util.Log;
 import android.widget.TextView;
 import android.widget.Toast;
@@ -44,6 +46,10 @@
     private Map<Integer, Integer> mCount;
     private int[] mPowerLevel;
 
+    private TextView mTimerText;
+    private CountDownTimer mTimer;
+    private static final long REFRESH_MAC_TIME = 930000; // 15.5 min
+
     private static final int[] POWER_DBM = {-21, -15, -7, 1, 9};
 
     @Override
@@ -54,9 +60,25 @@
         setInfoResources(R.string.ble_power_level_name,
                          R.string.ble_power_level_info, -1);
 
-        mCount = new HashMap<Integer, Integer>();
+        mTimerText = (TextView)findViewById(R.id.ble_timer);
+        mTimer = new CountDownTimer(REFRESH_MAC_TIME, 1000) {
+            @Override
+            public void onTick(long millis) {
+                int min = (int)millis / 60000;
+                int sec = ((int)millis / 1000) % 60;
+                mTimerText.setText(min + ":" + sec);
+            }
+
+            @Override
+            public void onFinish() {
+                mTimerText.setTextColor(getResources().getColor(R.color.red));
+                mTimerText.setText("Time is up!");
+            }
+        };
+
         mRssiText = new HashMap<Integer, TextView>();
         mCountText = new HashMap<Integer, TextView>();
+        mCount = null;
         mMacText = new HashMap<Integer, TextView>();
         mSetPowerText = new HashMap<Integer, TextView>();
         mPowerLevel = new int[]{AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW,
@@ -64,9 +86,6 @@
             AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM,
             AdvertiseSettings.ADVERTISE_TX_POWER_HIGH};
 
-        for (int i : mPowerLevel) {
-            mCount.put(i, 0);
-        }
         mMacText.put(AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW,
             (TextView)findViewById(R.id.ble_ultra_low_mac));
         mMacText.put(AdvertiseSettings.ADVERTISE_TX_POWER_LOW,
@@ -114,6 +133,7 @@
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(BleScannerService.BLE_POWER_LEVEL);
+        filter.addAction(BleScannerService.BLE_PRIVACY_NEW_MAC_RECEIVE);
         registerReceiver(onBroadcast, filter);
     }
 
@@ -135,26 +155,43 @@
             switch (intent.getAction()) {
                 case BleScannerService.BLE_POWER_LEVEL:
                     int powerLevelBit = intent.getIntExtra(
-                        BleScannerService.EXTRA_POWER_LEVEL_BIT, -1);
+                            BleScannerService.EXTRA_POWER_LEVEL_BIT, -1);
                     int powerLevel = intent.getIntExtra(BleScannerService.EXTRA_POWER_LEVEL, -2);
                     if (powerLevelBit < 0 || powerLevelBit > 3) {
-                      Toast.makeText(context, "Invalid power level", Toast.LENGTH_SHORT).show();
-                      break;
+                        Toast.makeText(context, "Invalid power level", Toast.LENGTH_SHORT).show();
+                        break;
+                    }
+
+                    if (mCount == null) {
+                        mCount = new HashMap<Integer, Integer>();
+                        for (int i : mPowerLevel) {
+                            mCount.put(i, 0);
+                        }
+                        mTimer.start();
                     }
                     Integer t = mCount.get(powerLevelBit) + 1;
                     mCount.put(powerLevelBit, t);
                     mCountText.get(powerLevelBit).setText(t.toString());
+
                     mMacText.get(powerLevelBit)
                         .setText(intent.getStringExtra(BleScannerService.EXTRA_MAC_ADDRESS));
                     mRssiText.get(powerLevelBit)
                         .setText(intent.getStringExtra(BleScannerService.EXTRA_RSSI));
-                    if (POWER_DBM[powerLevelBit] == powerLevel) {
+                    if (Math.abs(POWER_DBM[powerLevelBit] - powerLevel) < 2) {
                         mSetPowerText.get(powerLevelBit).setText("Valid power level");
                     } else {
                         mSetPowerText.get(powerLevelBit)
                             .setText("Unknown BLe advertise tx power: " + powerLevel);
                     }
                     break;
+                case BleScannerService.BLE_PRIVACY_NEW_MAC_RECEIVE:
+                     Toast.makeText(context, "New MAC address detected", Toast.LENGTH_SHORT)
+                            .show();
+                     mTimerText.setTextColor(getResources().getColor(R.color.green));
+                     mTimerText.append("   Get new MAC address.");
+                     mTimer.cancel();
+                     getPassButton().setEnabled(true);
+                     break;
             }
         }
     };
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerPrivacyMacActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerPrivacyMacActivity.java
deleted file mode 100644
index b7e4129..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerPrivacyMacActivity.java
+++ /dev/null
@@ -1,138 +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 com.android.cts.verifier.bluetooth;
-
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.os.CountDownTimer;
-import android.widget.TextView;
-import android.widget.Toast;
-
-public class BleScannerPrivacyMacActivity extends PassFailButtons.Activity {
-
-    private static final String TAG = "BleScannerPrivacyMac";
-
-    private int mMacCount;
-    private int mRespCount;
-    private TextView mMacText;
-    private TextView mCountText;
-    private TextView mRespText;
-    private TextView mTimerText;
-    private CountDownTimer mTimer;
-    private static final long REFRESH_MAC_TIME = 930000; // 15.5 min
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.ble_scanner_privacy_mac);
-        setPassFailButtonClickListeners();
-        setInfoResources(R.string.ble_privacy_mac_name,
-                         R.string.ble_privacy_mac_info, -1);
-        getPassButton().setEnabled(false);
-        mMacCount = 0;
-        mRespCount = 0;
-        mMacText = (TextView)findViewById(R.id.ble_mac_address);
-        mCountText = (TextView)findViewById(R.id.ble_mac_count);
-        mRespText = (TextView)findViewById(R.id.ble_resp_count);
-        mTimerText = (TextView)findViewById(R.id.ble_timer);
-
-        mTimer = new CountDownTimer(REFRESH_MAC_TIME, 1000) {
-            @Override
-            public void onTick(long millis) {
-                int min = (int)millis / 60000;
-                int sec = ((int)millis / 1000) % 60;
-                mTimerText.setText(min + ":" + sec);
-            }
-
-            @Override
-            public void onFinish() {
-                mTimerText.setTextColor(getResources().getColor(R.color.red));
-                mTimerText.setText("Time is up!");
-                stop();
-            }
-        };
-
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(BleScannerService.BLE_PRIVACY_NEW_MAC_RECEIVE);
-        filter.addAction(BleScannerService.BLE_MAC_ADDRESS);
-        filter.addAction(BleScannerService.BLE_SCAN_RESP);
-        registerReceiver(onBroadcast, filter);
-
-        if (mMacCount == 0) {
-            Intent intent = new Intent(this, BleScannerService.class);
-            intent.putExtra(BleScannerService.EXTRA_COMMAND, BleScannerService.COMMAND_PRIVACY_MAC);
-            startService(intent);
-        }
-    }
-
-
-    private BroadcastReceiver onBroadcast = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            switch (intent.getAction()) {
-                case BleScannerService.BLE_PRIVACY_NEW_MAC_RECEIVE:
-                    mMacText.append(", " + intent.getStringExtra(BleScannerService.EXTRA_MAC_ADDRESS));
-                    Toast.makeText(context, "New MAC address detected", Toast.LENGTH_SHORT).show();
-                    mTimerText.setTextColor(getResources().getColor(R.color.green));
-                    mTimerText.append("   Get new MAC address.");
-                    mTimer.cancel();
-                    getPassButton().setEnabled(true);
-                    break;
-                case BleScannerService.BLE_MAC_ADDRESS:
-                    if (mMacCount == 0) {
-                        mMacText.setText(intent.getStringExtra(BleScannerService.EXTRA_MAC_ADDRESS));
-                        mTimer.start();
-                    }
-                    mMacCount++;
-                    mCountText.setText("Count: " + mMacCount);
-                    break;
-                case BleScannerService.BLE_SCAN_RESP:
-                    mRespCount++;
-                    mRespText.setText("Response: " + mRespCount);
-                    break;
-            }
-        }
-    };
-
-    @Override
-    public void onPause() {
-        super.onPause();
-        unregisterReceiver(onBroadcast);
-    }
-
-    private void stop() {
-        stopService(new Intent(this, BleScannerService.class));
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        stop();
-    }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerService.java
index c8e7953..d3d96ac 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleScannerService.java
@@ -19,6 +19,7 @@
 import android.app.Service;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothManager;
+import android.bluetooth.le.AdvertiseSettings;
 import android.bluetooth.le.BluetoothLeScanner;
 import android.bluetooth.le.ScanCallback;
 import android.bluetooth.le.ScanFilter;
@@ -44,7 +45,6 @@
     public static final boolean DEBUG = true;
     public static final String TAG = "BleScannerService";
 
-    public static final int COMMAND_PRIVACY_MAC = 0;
     public static final int COMMAND_POWER_LEVEL = 1;
     public static final int COMMAND_SCAN_WITH_FILTER = 2;
     public static final int COMMAND_SCAN_WITHOUT_FILTER = 3;
@@ -105,21 +105,6 @@
 
             int command = intent.getIntExtra(EXTRA_COMMAND, -1);
             switch (command) {
-                case COMMAND_PRIVACY_MAC:
-                    filters.add(new ScanFilter.Builder()
-                        .setManufacturerData(MANUFACTURER_TEST_ID,
-                            new byte[]{MANUFACTURER_TEST_ID, 0})
-                        .setServiceData(new ParcelUuid(BleAdvertiserService.PRIVACY_MAC_UUID),
-                            BleAdvertiserService.PRIVACY_MAC_DATA)
-                        .build());
-                    filters.add(new ScanFilter.Builder()
-                        .setManufacturerData(MANUFACTURER_TEST_ID,
-                            new byte[]{MANUFACTURER_TEST_ID, 0})
-                        .setServiceData(new ParcelUuid(BleAdvertiserService.SCAN_RESP_UUID),
-                            BleAdvertiserService.PRIVACY_RESPONSE)
-                        .build());
-                    settingBuilder.setScanMode(ScanSettings.SCAN_MODE_BALANCED);
-                    break;
                 case COMMAND_POWER_LEVEL:
                     filters.add(new ScanFilter.Builder()
                         .setManufacturerData(MANUFACTURER_TEST_ID,
@@ -182,21 +167,6 @@
             String mac = result.getDevice().getAddress();
             Map<ParcelUuid, byte[]> serviceData = record.getServiceData();
 
-            if (serviceData.get(new ParcelUuid(BleAdvertiserService.PRIVACY_MAC_UUID)) != null) {
-                Intent privacyIntent = new Intent(BLE_MAC_ADDRESS);
-                privacyIntent.putExtra(EXTRA_MAC_ADDRESS, mac);
-                sendBroadcast(privacyIntent);
-
-                if (mOldMac == null) {
-                    mOldMac = mac;
-                } else if (!mOldMac.equals(mac)) {
-                    mOldMac = mac;
-                    Intent newIntent = new Intent(BLE_PRIVACY_NEW_MAC_RECEIVE);
-                    newIntent.putExtra(EXTRA_MAC_ADDRESS, mac);
-                    sendBroadcast(newIntent);
-                }
-            }
-
             if (serviceData.get(new ParcelUuid(BleAdvertiserService.POWER_LEVEL_UUID)) != null) {
                 byte[] data =
                         serviceData.get(new ParcelUuid(BleAdvertiserService.POWER_LEVEL_UUID));
@@ -207,6 +177,18 @@
                     powerIntent.putExtra(EXTRA_RSSI, new Integer(result.getRssi()).toString());
                     powerIntent.putExtra(EXTRA_POWER_LEVEL_BIT, (int)data[2]);
                     sendBroadcast(powerIntent);
+
+                    // Check privacy mac.
+                    if (data[2] == AdvertiseSettings.ADVERTISE_TX_POWER_HIGH) {
+                        String newMac = result.getDevice().getAddress();
+                        if (mOldMac == null) {
+                            mOldMac = newMac;
+                        } else if (!mOldMac.equals(mac)) {
+                            mOldMac = newMac;
+                            Intent newIntent = new Intent(BLE_PRIVACY_NEW_MAC_RECEIVE);
+                            sendBroadcast(newIntent);
+                        }
+                    }
                 }
             }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/PhotoCaptureActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/PhotoCaptureActivity.java
index 178a811..e5af6ba 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/PhotoCaptureActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/PhotoCaptureActivity.java
@@ -77,6 +77,8 @@
     private int mResolutionSpinnerIndex = -1;
     private WakeLock mWakeLock;
     private long shutterStartTime;
+    private int mPreviewOrientation;
+    private int mJpegOrientation;
 
     private ArrayList<Integer> mPreviewSizeCamerasToProcess = new ArrayList<Integer>();
 
@@ -171,7 +173,7 @@
                     mReportedFovPrePictureTaken = mCamera.getParameters().getHorizontalViewAngle();
 
                     mResolutionSpinnerIndex = position;
-                    initializeCamera();
+                    startPreview();
                 }
             }
 
@@ -395,6 +397,10 @@
     }
 
     private void initializeCamera() {
+        initializeCamera(true);
+    }
+
+    private void initializeCamera(boolean startPreviewAfterInit) {
         if (mCamera == null || mSurfaceHolder.getSurface() == null) {
             return;
         }
@@ -406,6 +412,8 @@
             Toast.makeText(this, t.getMessage(), Toast.LENGTH_LONG).show();
             return;
         }
+
+        calculateOrientations(this, mSelectedResolution.cameraId, mCamera);
         Camera.Parameters params = setCameraParams(mCamera);
 
         // Either use chosen preview size for current camera or automatically
@@ -417,18 +425,21 @@
             mCamera.setParameters(params);
             mCameraInitialized = true;
         }
-        startPreview();
+
+        if (startPreviewAfterInit) {
+          startPreview();
+        }
     }
 
     private void startPreview() {
         if (mCameraInitialized && mCamera != null) {
-            setCameraDisplayOrientation(this, mSelectedResolution.cameraId, mCamera);
+            mCamera.setDisplayOrientation(mPreviewOrientation);
             mCamera.startPreview();
             mPreviewActive = true;
         }
     }
 
-    private void switchToCamera(SelectableResolution resolution, boolean initializeCamera) {
+    private void switchToCamera(SelectableResolution resolution, boolean startPreview) {
         if (mCamera != null) {
             mCamera.stopPreview();
             mCamera.release();
@@ -437,9 +448,7 @@
         mSelectedResolution = resolution;
         mCamera = Camera.open(mSelectedResolution.cameraId);
 
-        if (initializeCamera){
-          initializeCamera();
-        }
+        initializeCamera(startPreview);
     }
 
     /**
@@ -474,6 +483,7 @@
         Camera.Parameters params = camera.getParameters();
         params.setJpegThumbnailSize(0, 0);
         params.setJpegQuality(100);
+        params.setRotation(mJpegOrientation);
         params.setFocusMode(getFocusMode(camera));
         params.setZoom(0);
         params.setPictureSize(mSelectedResolution.width, mSelectedResolution.height);
@@ -501,7 +511,7 @@
         return result;
     }
 
-    public static void setCameraDisplayOrientation(Activity activity,
+    private void calculateOrientations(Activity activity,
             int cameraId, android.hardware.Camera camera) {
         android.hardware.Camera.CameraInfo info =
                 new android.hardware.Camera.CameraInfo();
@@ -516,13 +526,12 @@
             case Surface.ROTATION_270: degrees = 270; break;
         }
 
-        int result;
         if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
-            result = (info.orientation + degrees) % 360;
-            result = (360 - result) % 360;  // compensate the mirror
+            mJpegOrientation = (info.orientation + degrees) % 360;
+            mPreviewOrientation = (360 - mJpegOrientation) % 360;  // compensate the mirror
         } else {  // back-facing
-            result = (info.orientation - degrees + 360) % 360;
+            mJpegOrientation = (info.orientation - degrees + 360) % 360;
+            mPreviewOrientation = mJpegOrientation;
         }
-        camera.setDisplayOrientation(result);
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/video/CameraVideoActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/video/CameraVideoActivity.java
index 97c0521..0a0e830 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/video/CameraVideoActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/video/CameraVideoActivity.java
@@ -70,6 +70,7 @@
     private int mPreviewTexWidth;
     private int mPreviewTexHeight;
     private int mPreviewRotation;
+    private int mVideoRotation;
 
     private VideoView mPlaybackView;
 
@@ -162,7 +163,10 @@
         // Step 5: set preview output
         // This is not necessary since preview has been taken care of
 
-        // Step 6: prepare configured MediaRecorder
+        // Step 6: set orientation hint
+        mMediaRecorder.setOrientationHint(mVideoRotation);
+
+        // Step 7: prepare configured MediaRecorder
         try {
             mMediaRecorder.prepare();
         } catch (IOException e) {
@@ -644,10 +648,11 @@
         }
 
         if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
-            mPreviewRotation = (info.orientation + degrees) % 360;
-            mPreviewRotation = (360 - mPreviewRotation) % 360;  // compensate the mirror
+            mVideoRotation = (info.orientation + degrees) % 360;
+            mPreviewRotation = (360 - mVideoRotation) % 360;  // compensate the mirror
         } else {  // back-facing
-            mPreviewRotation = (info.orientation - degrees + 360) % 360;
+            mVideoRotation = (info.orientation - degrees + 360) % 360;
+            mPreviewRotation = mVideoRotation;
         }
         if (mPreviewRotation != 0 && mPreviewRotation != 180) {
             Log.w(TAG,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
index 032442b..74a5317 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
@@ -169,6 +169,10 @@
     };
 
     public static final Feature[] ALL_JELLY_BEAN_FEATURES = {
+            // Required features in prior releases that became optional
+            new Feature(PackageManager.FEATURE_FAKETOUCH, false),
+
+            //new feature in JB
             new Feature(PackageManager.FEATURE_TELEVISION, false),
     };
 
@@ -190,13 +194,37 @@
 
     public static final Feature[] ALL_KITKAT_WATCH_FEATURES = {
             new Feature(PackageManager.FEATURE_SENSOR_HEART_RATE, false),
+            new Feature(PackageManager.FEATURE_BACKUP, false),
+            new Feature(PackageManager.FEATURE_PRINTING, false),
+            new Feature(PackageManager.FEATURE_WATCH, false),
+            new Feature(PackageManager.FEATURE_WEBVIEW, false),
+            new Feature(PackageManager.FEATURE_CAMERA_EXTERNAL, false),
     };
 
-    public static final Feature[] ALL_LMP_FEATURES = {
+    public static final Feature[] ALL_LOLLIPOP_FEATURES = {
+            // New features in L
+            new Feature(PackageManager.FEATURE_AUDIO_OUTPUT, false),
+            new Feature(PackageManager.FEATURE_CAMERA_CAPABILITY_MANUAL_POST_PROCESSING, false),
+            new Feature(PackageManager.FEATURE_CAMERA_CAPABILITY_MANUAL_SENSOR, false),
+            new Feature(PackageManager.FEATURE_CAMERA_CAPABILITY_RAW, false),
+            new Feature(PackageManager.FEATURE_CAMERA_LEVEL_FULL, false),
+            new Feature(PackageManager.FEATURE_CONNECTION_SERVICE, false),
+            new Feature(PackageManager.FEATURE_GAMEPAD, false),
+            new Feature(PackageManager.FEATURE_LEANBACK, false),
+            new Feature(PackageManager.FEATURE_LIVE_TV, false),
+            new Feature(PackageManager.FEATURE_MANAGED_USERS, false),
+            new Feature(PackageManager.FEATURE_OPENGLES_EXTENSION_PACK, false),
+            new Feature(PackageManager.FEATURE_SECURELY_REMOVES_USERS, false),
+            new Feature(PackageManager.FEATURE_SENSOR_AMBIENT_TEMPERATURE, false),
             new Feature(PackageManager.FEATURE_SENSOR_HEART_RATE_ECG, false),
+            new Feature(PackageManager.FEATURE_SENSOR_RELATIVE_HUMIDITY, false),
+            new Feature(PackageManager.FEATURE_VERIFIED_BOOT, false),
+
+            // New hidden features in L
             new Feature("android.hardware.ethernet", false),
-            new Feature("android.software.backup", false),
-            new Feature("android.software.print", false),
+            new Feature("android.hardware.hdmi.cec", false),
+            new Feature("android.software.leanback_only", false),
+            new Feature("android.software.voice_recognizers", false),
     };
 
     @Override
@@ -230,7 +258,7 @@
         // add features from latest to last so that the latest requirements are put in the set first
         int apiVersion = Build.VERSION.SDK_INT;
         if (apiVersion >= Build.VERSION_CODES.LOLLIPOP) {
-            Collections.addAll(features, ALL_LMP_FEATURES);
+            Collections.addAll(features, ALL_LOLLIPOP_FEATURES);
         }
         if (apiVersion >= Build.VERSION_CODES.KITKAT_WATCH) {
             Collections.addAll(features, ALL_KITKAT_WATCH_FEATURES);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ChargingConstraintTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ChargingConstraintTestActivity.java
new file mode 100644
index 0000000..2a94ace
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ChargingConstraintTestActivity.java
@@ -0,0 +1,184 @@
+package com.android.cts.verifier.jobscheduler;
+
+import android.annotation.TargetApi;
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.widget.Button;
+import android.widget.ImageView;
+
+import com.android.cts.verifier.R;
+
+/**
+ *  This activity runs the following tests:
+ *     - Ask the tester to unplug the phone, and verify that jobs with charging constraints will
+ *      not run.
+ *     - Ask the tester to ensure the phone is plugged in, and verify that jobs with charging
+ *      constraints are run.
+ */
+@TargetApi(21)
+public class ChargingConstraintTestActivity extends ConstraintTestActivity {
+
+    private static final int ON_CHARGING_JOB_ID =
+            ChargingConstraintTestActivity.class.hashCode() + 0;
+    private static final int OFF_CHARGING_JOB_ID =
+            ChargingConstraintTestActivity.class.hashCode() + 1;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Set up the UI.
+        setContentView(R.layout.js_charging);
+        setPassFailButtonClickListeners();
+        setInfoResources(R.string.js_charging_test, R.string.js_charging_instructions, -1);
+        mStartButton = (Button) findViewById(R.id.js_charging_start_test_button);
+
+        mJobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
+
+        // Register receiver for connected/disconnected power events.
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_POWER_CONNECTED);
+        intentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
+
+        registerReceiver(mChargingChangedReceiver, intentFilter);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        unregisterReceiver(mChargingChangedReceiver);
+    }
+
+    @Override
+    public void startTestImpl() {
+        new TestDeviceUnpluggedConstraint().execute();
+    }
+
+    private BroadcastReceiver mChargingChangedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_POWER_DISCONNECTED.equals(intent.getAction())) {
+                mDeviceUnpluggedTestPassed = false;
+                mStartButton.setEnabled(true);
+            } else if (Intent.ACTION_POWER_CONNECTED.equals(intent.getAction())) {
+                mStartButton.setEnabled(false);
+                if (mDeviceUnpluggedTestPassed) {
+                    continueTest();
+                }
+            }
+        }
+    };
+
+    /** Simple state boolean we use to determine whether to continue with the second test. */
+    private boolean mDeviceUnpluggedTestPassed = false;
+
+    /**
+     * After the first test has passed, and preconditions are met, this will kick off the second
+     * test.
+     * See {@link #startTest(android.view.View)}.
+     */
+    private void continueTest() {
+        new TestDevicePluggedInConstraint().execute();
+    }
+
+    /**
+     * Test blocks and can't be run on the main thread.
+     */
+    private void testChargingConstraintFails_notCharging() {
+        mTestEnvironment.setUp();
+
+        mTestEnvironment.setExpectedExecutions(0);
+        JobInfo runOnCharge = new JobInfo.Builder(OFF_CHARGING_JOB_ID, mMockComponent)
+                .setRequiresCharging(true)
+                .build();
+        mJobScheduler.schedule(runOnCharge);
+
+        // Send intent to kick off any jobs. This will be a no-op as the device is not plugged in;
+        // the JobScheduler tracks charging state independently.
+        sendBroadcastAndBlockForResult(EXPEDITE_STABLE_CHARGING);
+
+        boolean testPassed;
+        try {
+            testPassed = mTestEnvironment.awaitTimeout();
+        } catch (InterruptedException e) {
+            testPassed = false;
+        }
+        mDeviceUnpluggedTestPassed = testPassed;
+        runOnUiThread(new ChargingConstraintTestResultRunner(OFF_CHARGING_JOB_ID, testPassed));
+    }
+
+    /**
+     * Test blocks and can't be run on the main thread.
+     */
+    private void testChargingConstraintExecutes_onCharging() {
+        mTestEnvironment.setUp();
+
+        JobInfo delayConstraintAndUnexpiredDeadline =
+                new JobInfo.Builder(ON_CHARGING_JOB_ID, mMockComponent)
+                        .setRequiresCharging(true)
+                        .build();
+
+        mTestEnvironment.setExpectedExecutions(1);
+        mJobScheduler.schedule(delayConstraintAndUnexpiredDeadline);
+
+        // Force the JobScheduler to consider any jobs that have charging constraints.
+        sendBroadcast(EXPEDITE_STABLE_CHARGING);
+
+        boolean testPassed;
+        try {
+            testPassed = mTestEnvironment.awaitExecution();
+        } catch (InterruptedException e) {
+            testPassed = false;
+        }
+        runOnUiThread(new ChargingConstraintTestResultRunner(ON_CHARGING_JOB_ID, testPassed));
+    }
+
+    /** Run test for when the <bold>device is not connected to power.</bold>. */
+    private class TestDeviceUnpluggedConstraint extends AsyncTask<Void, Void, Void> {
+        @Override
+        protected Void doInBackground(Void... voids) {
+            testChargingConstraintFails_notCharging();
+
+            // Do not call notifyTestCompleted here, as we're still waiting for the user to put
+            // the device back on charge to continue with TestDevicePluggedInConstraint.
+            return null;
+        }
+    }
+
+    /** Run test for when the <bold>device is connected to power.</bold> */
+    private class TestDevicePluggedInConstraint extends AsyncTask<Void, Void, Void> {
+        @Override
+        protected Void doInBackground(Void... voids) {
+            testChargingConstraintExecutes_onCharging();
+
+            notifyTestCompleted();
+            return null;
+        }
+    }
+
+    private class ChargingConstraintTestResultRunner extends TestResultRunner {
+        ChargingConstraintTestResultRunner(int jobId, boolean testPassed) {
+            super(jobId, testPassed);
+        }
+
+        @Override
+        public void run() {
+            ImageView view;
+            if (mJobId == OFF_CHARGING_JOB_ID) {
+                view = (ImageView) findViewById(R.id.charging_off_test_image);
+            } else if (mJobId == ON_CHARGING_JOB_ID) {
+                view = (ImageView) findViewById(R.id.charging_on_test_image);
+            } else {
+                noteInvalidTest();
+                return;
+            }
+            view.setImageResource(mTestPassed ? R.drawable.fs_good : R.drawable.fs_error);
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConnectivityConstraintTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConnectivityConstraintTestActivity.java
new file mode 100644
index 0000000..e97539d
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConnectivityConstraintTestActivity.java
@@ -0,0 +1,184 @@
+package com.android.cts.verifier.jobscheduler;
+
+import android.annotation.TargetApi;
+import android.app.job.JobInfo;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.Button;
+import android.widget.ImageView;
+
+import com.android.cts.verifier.R;
+
+/**
+ * The majority of the connectivity constraints are done in the device-side test app
+ * android.jobscheduler.cts.deviceside. However a manual tester is required to completely turn off
+ * connectivity on the device in order to verify that jobs with connectivity constraints will not
+ * run in the absence of an internet connection.
+ */
+@TargetApi(21)
+public class ConnectivityConstraintTestActivity extends ConstraintTestActivity {
+    private static final String TAG = "ConnectivityConstraintTestActivity";
+    private static final int ANY_CONNECTIVITY_JOB_ID =
+            ConnectivityConstraintTestActivity.class.hashCode() + 0;
+    private static final int UNMETERED_CONNECTIVITY_JOB_ID =
+            ConnectivityConstraintTestActivity.class.hashCode() + 1;
+    private static final int NO_CONNECTIVITY_JOB_ID =
+            ConnectivityConstraintTestActivity.class.hashCode() + 2;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Set up the UI.
+        setContentView(R.layout.js_connectivity);
+        setPassFailButtonClickListeners();
+        setInfoResources(R.string.js_connectivity_test, R.string.js_connectivity_instructions, -1);
+        mStartButton = (Button) findViewById(R.id.js_connectivity_start_test_button);
+
+        // Disable test start if there is data connectivity.
+        mStartButton.setEnabled(isDataUnavailable());
+        // Register receiver to listen for connectivity changes.
+        IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
+        registerReceiver(mConnectivityChangedReceiver, intentFilter);
+
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        unregisterReceiver(mConnectivityChangedReceiver);
+    }
+
+    @Override
+    protected void startTestImpl() {
+        new TestConnectivityConstraint().execute();
+    }
+
+    /** Ensure that there's no connectivity before we allow the test to start. */
+    BroadcastReceiver mConnectivityChangedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Log.d(TAG, "received: " + intent);
+            String extras = "";
+            for (String name : intent.getExtras().keySet()) {
+                extras += " |" + name + " " + intent.getExtras().get(name) + "|";
+
+            }
+            Log.d(TAG, "extras: " + extras);
+            if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
+                // Only enable the test when we know there is no connectivity.
+                mStartButton.setEnabled(isDataUnavailable());
+            }
+        }
+    };
+
+    private void testUnmeteredConstraintFails_noConnectivity() {
+        testConnectivityConstraintFailsImpl(
+                JobInfo.NETWORK_TYPE_UNMETERED, UNMETERED_CONNECTIVITY_JOB_ID);
+    }
+
+    private void testAnyConnectivityConstraintFails_noConnectivity() {
+        testConnectivityConstraintFailsImpl(JobInfo.NETWORK_TYPE_ANY, ANY_CONNECTIVITY_JOB_ID);
+    }
+
+    private void testNoConnectivityConstraintExecutes_noConnectivity() {
+        JobInfo testJob = new JobInfo.Builder(NO_CONNECTIVITY_JOB_ID, mMockComponent)
+                .setRequiredNetworkType(JobInfo.NETWORK_TYPE_NONE)
+                .setOverrideDeadline(100000L)  // Will not expire.
+                .build();
+
+        mTestEnvironment.setUp();
+        mTestEnvironment.setExpectedExecutions(1);
+
+        mJobScheduler.schedule(testJob);
+
+        // Send intent to kick off ready jobs that the JobScheduler might be lazily holding on to.
+        sendBroadcastAndBlockForResult(EXPEDITE_STABLE_CHARGING);
+
+        boolean testPassed;
+        try {
+            testPassed = mTestEnvironment.awaitExecution();
+        } catch (InterruptedException e) {
+            testPassed = false;
+        }
+        runOnUiThread(
+                new ConnectivityConstraintTestResultRunner(NO_CONNECTIVITY_JOB_ID, testPassed));
+    }
+
+    private void testConnectivityConstraintFailsImpl(int requiredNetworkType, int jobId) {
+        // Use arguments provided to construct job with required connectivity constraint.
+        JobInfo testJob = new JobInfo.Builder(jobId, mMockComponent)
+                .setRequiredNetworkType(requiredNetworkType)
+                .build();
+
+        mTestEnvironment.setUp();
+        mTestEnvironment.setExpectedExecutions(0);
+
+        mJobScheduler.schedule(testJob);
+
+        // Send intent to kick off ready jobs that the JobScheduler might be lazily holding on to.
+        sendBroadcastAndBlockForResult(EXPEDITE_STABLE_CHARGING);
+
+        boolean testPassed;
+        try {
+            testPassed = mTestEnvironment.awaitTimeout();
+        } catch (InterruptedException e) {
+            testPassed = false;
+        }
+        runOnUiThread(
+                new ConnectivityConstraintTestResultRunner(jobId, testPassed));
+    }
+
+    /** Query the active network connection and return if there is no data connection. */
+    private boolean isDataUnavailable() {
+        final ConnectivityManager cm =
+                (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+        final NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
+
+        return (activeNetwork == null) ||
+                !activeNetwork.isConnectedOrConnecting();
+    }
+
+    private class TestConnectivityConstraint extends AsyncTask<Void, Void, Void> {
+
+        @Override
+        protected Void doInBackground(Void... voids) {
+            testUnmeteredConstraintFails_noConnectivity();
+            testAnyConnectivityConstraintFails_noConnectivity();
+            testNoConnectivityConstraintExecutes_noConnectivity();
+
+            notifyTestCompleted();
+            return null;
+        }
+    }
+
+    private class ConnectivityConstraintTestResultRunner extends TestResultRunner {
+        ConnectivityConstraintTestResultRunner(int jobId, boolean testPassed) {
+            super(jobId, testPassed);
+        }
+
+        @Override
+        public void run() {
+            ImageView view;
+            if (mJobId == ANY_CONNECTIVITY_JOB_ID) {
+                view = (ImageView) findViewById(R.id.connectivity_off_test_any_connectivity_image);
+            } else if (mJobId == UNMETERED_CONNECTIVITY_JOB_ID) {
+                view = (ImageView) findViewById(R.id.connectivity_off_test_unmetered_image);
+            } else if (mJobId == NO_CONNECTIVITY_JOB_ID) {
+                view = (ImageView) findViewById(R.id.connectivity_off_test_no_connectivity_image);
+            } else {
+                noteInvalidTest();
+                return;
+            }
+            view.setImageResource(mTestPassed ? R.drawable.fs_good : R.drawable.fs_error);
+        }
+    }
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConstraintTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConstraintTestActivity.java
new file mode 100644
index 0000000..da0862a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConstraintTestActivity.java
@@ -0,0 +1,115 @@
+package com.android.cts.verifier.jobscheduler;
+
+import android.annotation.TargetApi;
+import android.app.job.JobScheduler;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.Toast;
+
+import com.android.cts.verifier.PassFailButtons;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@TargetApi(21)
+public abstract class ConstraintTestActivity extends PassFailButtons.Activity {
+    /**
+     * Intent we use to force the job scheduler to consider any ready jobs that otherwise it may
+     * have decided to be lazy about.
+     */
+    protected static final Intent EXPEDITE_STABLE_CHARGING =
+            new Intent("com.android.server.task.controllers.BatteryController.ACTION_CHARGING_STABLE");
+
+    protected ComponentName mMockComponent;
+
+    protected MockJobService.TestEnvironment mTestEnvironment;
+    protected JobScheduler mJobScheduler;
+
+    /** Avoid cases where user might press "start test" more than once. */
+    private boolean mTestInProgress;
+    /**
+     * Starts the test - set up by subclass, which also controls the logic for how/when the test
+     * can be started.
+     */
+    protected Button mStartButton;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mJobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
+        mMockComponent = new ComponentName(this, MockJobService.class);
+        mTestEnvironment = MockJobService.TestEnvironment.getTestEnvironment();
+    }
+
+    /** OnClickListener for the "Start Test" ({@link #mStartButton}) button */
+    public final void startTest(View v) {
+        if (mTestInProgress) {
+            Toast toast =
+                    Toast.makeText(
+                            ConstraintTestActivity.this,
+                            "Test already in progress",
+                            Toast.LENGTH_SHORT);
+            toast.show();
+            return;
+        } else {
+            mTestInProgress = true;
+            startTestImpl();
+        }
+    }
+
+    /** Called by subclasses to allow the user to rerun the test if necessary. */
+    protected final void notifyTestCompleted() {
+        mTestInProgress = false;
+    }
+
+    /** Implemented by subclasses to determine logic for running the test. */
+    protected abstract void startTestImpl();
+
+    /**
+     * Broadcast the provided intent, and register a receiver to notify us after the broadcast has
+     * been processed.
+     * This function will block until the broadcast comes back, and <bold>cannot</bold> be called
+     * on the main thread.
+     * @return True if we received the callback, false if not.
+     */
+    protected boolean sendBroadcastAndBlockForResult(Intent intent) {
+        final CountDownLatch latch = new CountDownLatch(1);
+        sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                latch.countDown();
+            }
+        }, null, -1, null, null);
+        try {
+            return latch.await(5, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            return false;
+        }
+    }
+
+    /** Extended by test activities to report results of a test. */
+    protected abstract class TestResultRunner implements Runnable {
+        final int mJobId;
+        final boolean mTestPassed;
+
+        TestResultRunner(int jobId, boolean testPassed) {
+            mJobId = jobId;
+            mTestPassed = testPassed;
+        }
+        protected void noteInvalidTest() {
+            final Toast toast =
+                    Toast.makeText(
+                            ConstraintTestActivity.this,
+                            "Invalid result returned from test thread: job=" + mJobId + ", res="
+                                    + mTestPassed,
+                            Toast.LENGTH_SHORT);
+            toast.show();
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/IdleConstraintTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/IdleConstraintTestActivity.java
new file mode 100644
index 0000000..a8bd993
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/IdleConstraintTestActivity.java
@@ -0,0 +1,203 @@
+/*
+ * 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 com.android.cts.verifier.jobscheduler;
+
+import com.android.cts.verifier.R;
+
+import android.annotation.TargetApi;
+import android.app.job.JobInfo;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.Button;
+import android.widget.ImageView;
+
+/**
+ *  Idle constraints:
+ *      The framework doesn't support turning idle mode off. Use the manual tester to ensure that
+ *      the device is not in idle mode (by turning the screen off and then back on) before running
+ *      the tests.
+ */
+@TargetApi(21)
+public class IdleConstraintTestActivity extends ConstraintTestActivity {
+    private static final String TAG = "IdleModeTestActivity";
+    /**
+     * It takes >1hr for idle mode to be triggered. We'll use this secret broadcast to force the
+     * scheduler into idle. It's not a protected broadcast so that's alright.
+     */
+    private static final String ACTION_EXPEDITE_IDLE_MODE =
+            "com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE";
+
+    /**
+     * Id for the job that we schedule when the device is not in idle mode. This job is expected
+     * to not execute. Executing means that the verifier test should fail.
+     */
+    private static final int IDLE_OFF_JOB_ID = IdleConstraintTestActivity.class.hashCode() + 0;
+    /**
+     * Id for the job that we schedule when the device *is* in idle mode. This job is expected to
+     * execute. Not executing means that the verifier test should fail.
+     */
+    private static final int IDLE_ON_JOB_ID = IdleConstraintTestActivity.class.hashCode() + 1;
+
+    /**
+     * Listens for idle mode off/on events, namely {@link #ACTION_EXPEDITE_IDLE_MODE} and
+     * {@link Intent#ACTION_SCREEN_ON}.
+     * On ACTION_EXPEDITE_IDLE_MODE, we will disable the {@link #mStartButton}, and on
+     * ACTION_SCREEN_ON we enable it. This is to avoid the start button being clicked when the
+     * device is in idle mode.
+     */
+    private BroadcastReceiver mIdleChangedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) {
+                mStartButton.setEnabled(true);
+            } else if (ACTION_EXPEDITE_IDLE_MODE.equals(intent.getAction())) {
+                mStartButton.setEnabled(false);
+            } else {
+                Log.e(TAG, "Invalid broadcast received, was expecting SCREEN_ON");
+            }
+        }
+    };
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Set up the UI.
+        setContentView(R.layout.js_idle);
+        setPassFailButtonClickListeners();
+        setInfoResources(R.string.js_idle_test, R.string.js_idle_instructions, -1);
+        mStartButton = (Button) findViewById(R.id.js_idle_start_test_button);
+
+        // Register receiver for idle off/on events.
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
+        intentFilter.addAction(ACTION_EXPEDITE_IDLE_MODE);
+
+        registerReceiver(mIdleChangedReceiver, intentFilter);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        unregisterReceiver(mIdleChangedReceiver);
+    }
+
+    @Override
+    protected void startTestImpl() {
+        new TestIdleModeTask().execute();
+    }
+
+    /** Background task that will run the actual test. */
+    private class TestIdleModeTask extends AsyncTask<Void, Void, Void> {
+
+        @Override
+        protected Void doInBackground(Void... voids) {
+            testIdleConstraintFails_notIdle();
+
+
+            // Send the {@link #ACTION_EXPEDITE_IDLE_MODE} broadcast as an ordered broadcast, this
+            // function will block until all receivers have processed the broadcast.
+            if (!sendBroadcastAndBlockForResult(new Intent(ACTION_EXPEDITE_IDLE_MODE))) {
+                // Fail the test if the broadcast wasn't processed.
+                runOnUiThread(new IdleTestResultRunner(IDLE_ON_JOB_ID, false));
+            }
+
+            testIdleConstraintExecutes_onIdle();
+
+            notifyTestCompleted();
+            return null;
+        }
+
+    }
+
+    /**
+     * The user has just pressed the "Start Test" button, so we know that the device can't be idle.
+     * Schedule a job with an idle constraint and verify that it doesn't execute.
+     */
+    private void testIdleConstraintFails_notIdle() {
+        mTestEnvironment.setUp();
+        mJobScheduler.cancelAll();
+
+        mTestEnvironment.setExpectedExecutions(0);
+
+        mJobScheduler.schedule(
+                new JobInfo.Builder(IDLE_OFF_JOB_ID, mMockComponent)
+                        .setRequiresDeviceIdle(true)
+                        .build());
+
+        boolean testPassed;
+        try {
+            testPassed = mTestEnvironment.awaitTimeout();
+        } catch (InterruptedException e) {
+            // We'll just indicate that it failed, not why.
+            testPassed = false;
+        }
+        runOnUiThread(new IdleTestResultRunner(IDLE_OFF_JOB_ID, testPassed));
+    }
+
+    private void testIdleConstraintExecutes_onIdle() {
+        mTestEnvironment.setUp();
+        mJobScheduler.cancelAll();
+
+        mTestEnvironment.setExpectedExecutions(1);
+
+        mJobScheduler.schedule(
+                new JobInfo.Builder(IDLE_ON_JOB_ID, mMockComponent)
+                .setRequiresDeviceIdle(true)
+                .build());
+
+        boolean testPassed;
+        try {
+            testPassed = mTestEnvironment.awaitExecution();
+        } catch (InterruptedException e) {
+            // We'll just indicate that it failed, not why.
+            testPassed = false;
+        }
+        runOnUiThread(new IdleTestResultRunner(IDLE_ON_JOB_ID, testPassed));
+    }
+
+    /**
+     * Runnable to update the UI with the outcome of the test. This class only runs two tests, so
+     * the argument passed into the constructor will indicate which of the tests we are reporting
+     * for.
+     */
+    protected class IdleTestResultRunner extends TestResultRunner {
+
+        IdleTestResultRunner(int jobId, boolean testPassed) {
+            super(jobId, testPassed);
+        }
+
+        @Override
+        public void run() {
+            ImageView view;
+            if (mJobId == IDLE_OFF_JOB_ID) {
+                view = (ImageView) findViewById(R.id.idle_off_test_image);
+            } else if (mJobId == IDLE_ON_JOB_ID) {
+                view = (ImageView) findViewById(R.id.idle_on_test_image);
+            } else {
+                noteInvalidTest();
+                return;
+            }
+            view.setImageResource(mTestPassed ? R.drawable.fs_good : R.drawable.fs_error);
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/MockJobService.java b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/MockJobService.java
new file mode 100644
index 0000000..9595a6a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/MockJobService.java
@@ -0,0 +1,118 @@
+/*
+ * 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 com.android.cts.verifier.jobscheduler;
+
+import android.annotation.TargetApi;
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Handles callback from the framework {@link android.app.job.JobScheduler}. The behaviour of this
+ * class is configured through the static
+ * {@link TestEnvironment}.
+ */
+@TargetApi(21)
+public class MockJobService extends JobService {
+    private static final String TAG = "MockJobService";
+
+    /** Wait this long before timing out the test. */
+    private static final long DEFAULT_TIMEOUT_MILLIS = 5000L; // 5 seconds.
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        Log.e(TAG, "Created test service.");
+    }
+
+    @Override
+    public boolean onStartJob(JobParameters params) {
+        Log.i(TAG, "Test job executing: " + params.getJobId());
+
+        TestEnvironment.getTestEnvironment().notifyExecution(params.getJobId());
+        return false;  // No work to do.
+    }
+
+    @Override
+    public boolean onStopJob(JobParameters params) {
+        return false;
+    }
+
+    /**
+     * Configures the expected behaviour for each test. This object is shared across consecutive
+     * tests, so to clear state each test is responsible for calling
+     * {@link TestEnvironment#setUp()}.
+     */
+    public static final class TestEnvironment {
+
+        private static TestEnvironment kTestEnvironment;
+        public static final int INVALID_JOB_ID = -1;
+
+        private CountDownLatch mLatch;
+        private int mExecutedJobId;
+
+        public static TestEnvironment getTestEnvironment() {
+            if (kTestEnvironment == null) {
+                kTestEnvironment = new TestEnvironment();
+            }
+            return kTestEnvironment;
+        }
+
+        /**
+         * Block the test thread, waiting on the JobScheduler to execute some previously scheduled
+         * job on this service.
+         */
+        public boolean awaitExecution() throws InterruptedException {
+            final boolean executed = mLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+            return executed;
+        }
+
+        /**
+         * Block the test thread, expecting to timeout but still listening to ensure that no jobs
+         * land in the interim.
+         * @return True if the latch timed out waiting on an execution.
+         */
+        public boolean awaitTimeout() throws InterruptedException {
+            return !mLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+        }
+
+        private void notifyExecution(int jobId) {
+            Log.d(TAG, "Job executed:" + jobId);
+            mExecutedJobId = jobId;
+            mLatch.countDown();
+        }
+
+        public void setExpectedExecutions(int numExecutions) {
+            // For no executions expected, set count to 1 so we can still block for the timeout.
+            if (numExecutions == 0) {
+                mLatch = new CountDownLatch(1);
+            } else {
+                mLatch = new CountDownLatch(numExecutions);
+            }
+        }
+
+        /** Called in each testCase#setup */
+        public void setUp() {
+            mLatch = null;
+            mExecutedJobId = INVALID_JOB_ID;
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
index 3d0e0d7..b4863fa 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
@@ -31,7 +31,9 @@
 
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 public class MockListener extends NotificationListenerService {
     static final String TAG = "MockListener";
@@ -67,8 +69,10 @@
 
     private ArrayList<String> mPosted = new ArrayList<String>();
     private ArrayMap<String, JSONObject> mNotifications = new ArrayMap<>();
+    private ArrayMap<String, String> mNotificationKeys = new ArrayMap<>();
     private ArrayList<String> mRemoved = new ArrayList<String>();
     private ArrayList<String> mOrder = new ArrayList<>();
+    private Set<String> mTestPackages = new HashSet<>();
     private BroadcastReceiver mReceiver;
     private int mDND = -1;
 
@@ -77,6 +81,8 @@
         super.onCreate();
         Log.d(TAG, "created");
 
+        mTestPackages.add("com.android.cts.verifier");
+
         mPosted = new ArrayList<String>();
         mRemoved = new ArrayList<String>();
 
@@ -123,10 +129,13 @@
                     setResultCode(Activity.RESULT_OK);
                 } else if (SERVICE_CLEAR_ONE.equals(action)) {
                     Log.d(TAG, "SERVICE_CLEAR_ONE");
-                    MockListener.this.cancelNotification(
-                            context.getApplicationInfo().packageName,
-                            intent.getStringExtra(EXTRA_TAG),
-                            intent.getIntExtra(EXTRA_CODE, 0));
+                    String tag = intent.getStringExtra(EXTRA_TAG);
+                    String key = mNotificationKeys.get(tag);
+                    if (key != null) {
+                        MockListener.this.cancelNotification(key);
+                    } else {
+                        Log.w(TAG, "Notification does not exist: " + tag);
+                    }
                 } else if (SERVICE_CLEAR_ALL.equals(action)) {
                     Log.d(TAG, "SERVICE_CLEAR_ALL");
                     MockListener.this.cancelAllNotifications();
@@ -205,6 +214,7 @@
 
     @Override
     public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
+        if (!mTestPackages.contains(sbn.getPackageName())) { return; }
         Log.d(TAG, "posted: " + sbn.getTag());
         mPosted.add(sbn.getTag());
         JSONObject notification = new JSONObject();
@@ -216,6 +226,7 @@
             notification.put(JSON_ICON, sbn.getNotification().icon);
             notification.put(JSON_FLAGS, sbn.getNotification().flags);
             mNotifications.put(sbn.getKey(), notification);
+            mNotificationKeys.put(sbn.getTag(), sbn.getKey());
         } catch (JSONException e) {
             Log.e(TAG, "failed to pack up notification payload", e);
         }
@@ -228,6 +239,7 @@
         mRemoved.add(sbn.getTag());
         mNotifications.remove(sbn.getKey());
         onNotificationRankingUpdate(rankingMap);
+        mNotificationKeys.remove(sbn.getTag());
     }
 
     public static void resetListenerData(Context context) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationAttentionManagementVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationAttentionManagementVerifierActivity.java
index e355b07..b4e348f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationAttentionManagementVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationAttentionManagementVerifierActivity.java
@@ -82,6 +82,7 @@
         createAutoItem(R.string.nls_service_started);
         createAutoItem(R.string.attention_create_contacts);
         createRetryItem(R.string.attention_filter_none);
+        createAutoItem(R.string.attention_all_are_filtered);
         createRetryItem(R.string.attention_filter_all);
         createAutoItem(R.string.attention_none_are_filtered);
         createAutoItem(R.string.attention_default_order);
@@ -114,42 +115,45 @@
                 testModeNone(mState);
                 break;
             case 4:
-                testModeAll(mState);
+                testNoneInterceptsAll(mState);
                 break;
             case 5:
-                testALLInterceptsNothing(mState);
+                testModeAll(mState);
                 break;
             case 6:
-                testDefaultOrder(mState);
+                testAllInterceptsNothing(mState);
                 break;
             case 7:
-                testInterruptionOrder(mState);
+                testDefaultOrder(mState);
                 break;
             case 8:
-                testPrioritytOrder(mState);
+                testInterruptionOrder(mState);
                 break;
             case 9:
-                testAmbientBits(mState);
+                testPrioritytOrder(mState);
                 break;
             case 10:
-                testLookupUriOrder(mState);
+                testAmbientBits(mState);
                 break;
             case 11:
-                testEmailOrder(mState);
+                testLookupUriOrder(mState);
                 break;
             case 12:
-                testPhoneOrder(mState);
+                testEmailOrder(mState);
                 break;
             case 13:
-                testModePriority(mState);
+                testPhoneOrder(mState);
                 break;
             case 14:
-                testPriorityInterceptsSome(mState);
+                testModePriority(mState);
                 break;
             case 15:
-                testDeleteContacts(mState);
+                testPriorityInterceptsSome(mState);
                 break;
             case 16:
+                testDeleteContacts(mState);
+                break;
+            case 17:
                 getPassButton().setEnabled(true);
                 mNm.cancelAll();
                 break;
@@ -678,7 +682,7 @@
     }
 
     // Nothing should be filtered when mode is ALL
-    private void testALLInterceptsNothing(final int i) {
+    private void testAllInterceptsNothing(final int i) {
         if (mStatus[i] == SETUP) {
             mNm.cancelAll();
             MockListener.resetListenerData(this);
@@ -783,6 +787,59 @@
         }
     }
 
+    // Nothing should get through when mode is None.
+    private void testNoneInterceptsAll(final int i) {
+        if (mStatus[i] == SETUP) {
+            mNm.cancelAll();
+            MockListener.resetListenerData(this);
+            mStatus[i] = CLEARED;
+            // wait for intent to move through the system
+            delay();
+        } else if (mStatus[i] == CLEARED) {
+            sendNotifications(MODE_URI, false, false);
+            mStatus[i] = READY;
+            // wait for notifications to move through the system
+            delay();
+        } else {
+            MockListener.probeListenerPayloads(mContext,
+                    new MockListener.StringListResultCatcher() {
+                        @Override
+                        public void accept(List<String> result) {
+                            boolean pass = false;
+                            Set<String> found = new HashSet<String>();
+                            if (result != null && result.size() > 0) {
+                                pass = true;
+                                for (String payloadData : result) {
+                                    try {
+                                        JSONObject payload = new JSONObject(payloadData);
+                                        String tag = payload.getString(JSON_TAG);
+                                        if (found.contains(tag)) {
+                                            // multiple entries for same notification!
+                                            pass = false;
+                                        } else if (ALICE.equals(tag)) {
+                                            found.add(ALICE);
+                                            pass &= !payload.getBoolean(JSON_MATCHES_ZEN_FILTER);
+                                        } else if (BOB.equals(tag)) {
+                                            found.add(BOB);
+                                            pass &= !payload.getBoolean(JSON_MATCHES_ZEN_FILTER);
+                                        } else if (CHARLIE.equals(tag)) {
+                                            found.add(CHARLIE);
+                                            pass &= !payload.getBoolean(JSON_MATCHES_ZEN_FILTER);
+                                        }
+                                    } catch (JSONException e) {
+                                        pass = false;
+                                        Log.e(TAG, "failed to unpack data from mocklistener", e);
+                                    }
+                                }
+                            }
+                            pass &= found.size() == 3;
+                            mStatus[i] = pass ? PASS : FAIL;
+                            next();
+                        }
+                    });
+        }
+    }
+
     /** Search a list of notification keys for a givcen tag. */
     private int findTagInKeys(String tag, List<String> orderedKeys) {
         for (int i = 0; i < orderedKeys.size(); i++) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/projection/list/ListPresentation.java b/apps/CtsVerifier/src/com/android/cts/verifier/projection/list/ListPresentation.java
index dad4945..5dddf5c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/projection/list/ListPresentation.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/projection/list/ListPresentation.java
@@ -50,7 +50,7 @@
         setContentView(view);
 
         for (int i = 0; i < NUM_ITEMS; ++i) {
-            mItemList.add("Item #" + i);
+            mItemList.add("Item #" + 1 + i);
         }
 
         ListView listView = (ListView) view.findViewById(R.id.pla_list);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/projection/offscreen/ProjectionOffscreenActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/projection/offscreen/ProjectionOffscreenActivity.java
index f992618..510a03b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/projection/offscreen/ProjectionOffscreenActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/projection/offscreen/ProjectionOffscreenActivity.java
@@ -26,6 +26,9 @@
 import android.graphics.PixelFormat;
 import android.media.Image;
 import android.media.ImageReader;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -68,7 +71,7 @@
     protected TestStatus mTestStatus = TestStatus.RUNNING;
 
     private final Runnable sendKeyEventRunnable = new Runnable() {
-            @Override
+        @Override
         public void run() {
             try {
                 mService.onKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN));
@@ -79,15 +82,28 @@
         }
     };
 
+    private final Runnable playNotificationRunnable = new Runnable() {
+
+        @Override
+        public void run() {
+            Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
+            Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), notification);
+            r.play();
+        }
+    };
+
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
 
     @Override
     public void onReceive(Context context, Intent intent) {
         if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
-            new Handler(Looper.getMainLooper()).postDelayed(
+            Handler handler = new Handler(Looper.getMainLooper());
+            handler.postDelayed(
                     sendKeyEventRunnable, DELAYED_RUNNABLE_TIME);
             mStatusView.setText("Running test...");
             mTimeScreenTurnedOff = SystemClock.uptimeMillis();
+            // Notify user its safe to turn screen back on after 5s + fudge factor
+            handler.postDelayed(playNotificationRunnable, TIME_SCREEN_OFF + 500);
         } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
             if (SystemClock.uptimeMillis() - mTimeScreenTurnedOff < TIME_SCREEN_OFF) {
                 mStatusView.setText("ERROR: Turned on screen too early");
@@ -121,8 +137,9 @@
                     filter.addAction(Intent.ACTION_SCREEN_ON);
 
                     registerReceiver(mReceiver, filter);
-                    mStatusView.setText(
-                            "Please turn off your screen and turn it back on after 5 seconds");
+                    mStatusView.setText("Please turn off your screen and turn it back on after " +
+                            "5 seconds. A sound will be played when it is safe to turn the " +
+                            "screen back on");
                 }
 
             });
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BatchingTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BatchingTestActivity.java
index 4ba38a9..6f0a7aa 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BatchingTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BatchingTestActivity.java
@@ -19,15 +19,12 @@
 import com.android.cts.verifier.R;
 import com.android.cts.verifier.sensors.base.SensorCtsVerifierTestActivity;
 
-import android.content.Context;
 import android.hardware.Sensor;
 import android.hardware.SensorManager;
 import android.hardware.cts.helpers.TestSensorEnvironment;
 import android.hardware.cts.helpers.sensoroperations.TestSensorFlushOperation;
 import android.hardware.cts.helpers.sensoroperations.TestSensorOperation;
 import android.hardware.cts.helpers.sensoroperations.VerifiableSensorOperation;
-import android.os.Bundle;
-import android.os.PowerManager;
 
 import java.util.concurrent.TimeUnit;
 
@@ -51,27 +48,9 @@
     // such events to generate
     private static final int REPORT_LATENCY_25_SEC = 25;
 
-    private PowerManager.WakeLock mWakeLock;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-    }
-
-    @Override
-    protected void activitySetUp() throws InterruptedException {
-        PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
-        mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "BatchingTests");
-        mWakeLock.acquire();
-    }
-
-    @Override
-    protected void activityCleanUp() throws InterruptedException {
-        mWakeLock.release();
-    }
-
     // TODO: refactor to discover all available sensors of each type and dynamically generate test
     // cases for all of them
+    @SuppressWarnings("unused")
     public String testStepCounter_batching() throws Throwable {
         return runBatchTest(
                 Sensor.TYPE_STEP_COUNTER,
@@ -79,6 +58,7 @@
                 R.string.snsr_batching_walking_needed);
     }
 
+    @SuppressWarnings("unused")
     public String testStepCounter_flush() throws Throwable {
         return runFlushTest(
                 Sensor.TYPE_STEP_COUNTER,
@@ -86,6 +66,7 @@
                 R.string.snsr_batching_walking_needed);
     }
 
+    @SuppressWarnings("unused")
     public String testStepDetector_batching() throws Throwable {
         return  runBatchTest(
                 Sensor.TYPE_STEP_DETECTOR,
@@ -93,6 +74,7 @@
                 R.string.snsr_batching_walking_needed);
     }
 
+    @SuppressWarnings("unused")
     public String testStepDetector_flush() throws Throwable {
         return  runFlushTest(
                 Sensor.TYPE_STEP_DETECTOR,
@@ -100,6 +82,7 @@
                 R.string.snsr_batching_walking_needed);
     }
 
+    @SuppressWarnings("unused")
     public String testProximity_batching() throws Throwable {
         return runBatchTest(
                 Sensor.TYPE_PROXIMITY,
@@ -107,6 +90,7 @@
                 R.string.snsr_interaction_needed);
     }
 
+    @SuppressWarnings("unused")
     public String testProximity_flush() throws Throwable {
         return runFlushTest(
                 Sensor.TYPE_PROXIMITY,
@@ -114,6 +98,7 @@
                 R.string.snsr_interaction_needed);
     }
 
+    @SuppressWarnings("unused")
     public String testLight_batching() throws Throwable {
         return runBatchTest(
                 Sensor.TYPE_LIGHT,
@@ -121,6 +106,7 @@
                 R.string.snsr_interaction_needed);
     }
 
+    @SuppressWarnings("unused")
     public String testLight_flush() throws Throwable {
         return runFlushTest(
                 Sensor.TYPE_LIGHT,
@@ -164,7 +150,7 @@
         return executeTest(operation);
     }
 
-    private String executeTest(VerifiableSensorOperation operation) {
+    private String executeTest(VerifiableSensorOperation operation) throws InterruptedException {
         operation.addDefaultVerifications();
         operation.setLogEvents(true);
         operation.execute();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeMeasurementTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeMeasurementTestActivity.java
index ac63780..4b2a7f4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeMeasurementTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeMeasurementTestActivity.java
@@ -51,7 +51,7 @@
     }
 
     @Override
-    protected void activitySetUp() {
+    protected void activitySetUp() throws InterruptedException {
         getTestLogger().logInstructions(R.string.snsr_gyro_device_placement);
         waitForUserToContinue();
         initializeGlSurfaceView(mRenderer);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
index bd18a95..553147b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
@@ -46,7 +46,7 @@
     }
 
     @Override
-    public void activitySetUp() {
+    public void activitySetUp() throws InterruptedException {
         calibrateMagnetometer();
     }
 
@@ -165,7 +165,7 @@
     /**
      * A routine to help operators calibrate the magnetometer.
      */
-    private void calibrateMagnetometer() {
+    private void calibrateMagnetometer() throws InterruptedException {
         SensorEventListener2 listener = new SensorEventListener2() {
             @Override
             public void onSensorChanged(SensorEvent event) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RotationVectorTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RotationVectorTestActivity.java
index cd94128..6b804dd 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RotationVectorTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RotationVectorTestActivity.java
@@ -87,7 +87,7 @@
         // TODO: take reference value automatically when device is 'still'
         clearText();
         appendText(R.string.snsr_rotation_vector_set_reference);
-        waitForUser();
+        waitForUserToContinue();
 
         clearText();
         for (int i = 0; i < MAX_SENSORS_AVAILABLE; ++i) {
@@ -104,7 +104,7 @@
         // TODO: take final value automatically when device becomes 'still' at the end
         clearText();
         appendText(R.string.snsr_rotation_vector_set_final);
-        waitForUser();
+        waitForUserToContinue();
 
         clearText();
         closeGlSurfaceView();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SensorPowerTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SensorPowerTestActivity.java
index cfc4db0..8370d3e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SensorPowerTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SensorPowerTestActivity.java
@@ -34,11 +34,10 @@
         super(SensorPowerTestActivity.class);
     }
 
-
     @Override
-    public void waitForUserAcknowledgement(final String message) {
+    public void waitForUserAcknowledgement(final String message) throws InterruptedException {
         appendText(message);
-        waitForUser();
+        waitForUserToContinue();
     }
 
     @Override
@@ -63,7 +62,7 @@
     }
 
     @Override
-    protected void activitySetUp() {
+    protected void activitySetUp() throws InterruptedException {
         mScreenManipulator = new SensorTestScreenManipulator(getApplicationContext());
         mScreenManipulator.initialize(this);
     }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SensorSynchronizationTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SensorSynchronizationTestActivity.java
index 1dd5984..683430c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SensorSynchronizationTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SensorSynchronizationTestActivity.java
@@ -7,7 +7,6 @@
 
 import android.annotation.TargetApi;
 import android.content.Context;
-import android.graphics.Color;
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
@@ -137,9 +136,9 @@
     public String testCrossSensorSynchronization() throws Throwable {
         appendText("This test provides a rough indication of cross-sensor timestamp synchronization.");
         appendText("Hold device still in hand and click 'Next'");
-        waitForUser();
+        waitForUserToBegin();
         clearText();
-        appendText("Quickly twist device upside-down and back", Color.GREEN);
+        appendText("Quickly twist device upside-down and back");
 
         startDataCollection();
         Thread.sleep(DATA_COLLECTION_TIME_IN_MS);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java
index a84a045..faba445 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/SignificantMotionTestActivity.java
@@ -59,6 +59,8 @@
     /**
      * Test cases.
      */
+
+    @SuppressWarnings("unused")
     public String testTrigger() throws Throwable {
         return runTest(
                 R.string.snsr_significant_motion_test_trigger,
@@ -67,6 +69,7 @@
                 false /* vibrate */);
     }
 
+    @SuppressWarnings("unused")
     public String testNotTriggerAfterCancel() throws Throwable {
         return runTest(
                 R.string.snsr_significant_motion_test_cancel,
@@ -78,6 +81,7 @@
     /**
      * Verifies that Significant Motion is not trigger by the vibrator motion.
      */
+    @SuppressWarnings("unused")
     public String testVibratorDoesNotTrigger() throws Throwable {
      return runTest(
              R.string.snsr_significant_motion_test_vibration,
@@ -90,6 +94,7 @@
      * Verifies that the natural motion of keeping the device in hand does not change the location.
      * It ensures that Significant Motion will not trigger in that scenario.
      */
+    @SuppressWarnings("unused")
     public String testInHandDoesNotTrigger() throws Throwable {
         return runTest(
                 R.string.snsr_significant_motion_test_in_hand,
@@ -98,6 +103,7 @@
                 false /* vibrate */);
     }
 
+    @SuppressWarnings("unused")
     public String testSittingDoesNotTrigger() throws Throwable {
         return runTest(
                 R.string.snsr_significant_motion_test_sitting,
@@ -106,6 +112,7 @@
                 false /* vibrate */);
     }
 
+    @SuppressWarnings("unused")
     public String testTriggerDeactivation() throws Throwable {
         SensorTestLogger logger = getTestLogger();
         logger.logInstructions(R.string.snsr_significant_motion_test_deactivation);
@@ -167,6 +174,7 @@
             }
         } finally {
             mSensorManager.cancelTriggerSensor(verifier, mSensorSignificantMotion);
+            playSound();
         }
         return result;
     }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/StepCounterTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/StepCounterTestActivity.java
index 76d12d9..98368c6 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/StepCounterTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/StepCounterTestActivity.java
@@ -33,7 +33,6 @@
 import android.os.SystemClock;
 import android.view.MotionEvent;
 import android.view.View;
-import android.widget.ScrollView;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -86,8 +85,7 @@
                     "Sensors Step Counter/Detector are not supported.");
         }
 
-        ScrollView scrollView = (ScrollView) findViewById(R.id.log_scroll_view);
-        scrollView.setOnTouchListener(new View.OnTouchListener() {
+        setLogScrollViewListener(new View.OnTouchListener() {
             @Override
             public boolean onTouch(View v, MotionEvent event) {
                 // during movement of the device, the ScrollView will detect user taps as attempts
@@ -95,14 +93,27 @@
                 // to overcome the fact that a ScrollView cannot be disabled from scrolling, we
                 // listen for ACTION_UP events instead of click events in the child layout
                 long elapsedTime = SystemClock.elapsedRealtimeNanos();
-                if (event.getAction() == MotionEvent.ACTION_UP) {
+                if (event.getAction() != MotionEvent.ACTION_UP) {
+                    return false;
+                }
+
+                try {
                     logUserReportedStep(elapsedTime);
+                } catch (InterruptedException e) {
+                    // we cannot propagate the exception in the main thread, so we just catch and
+                    // restore the status, we don't need to log as we are terminating anyways
+                    Thread.currentThread().interrupt();
                 }
                 return false;
             }
         });
     }
 
+    @Override
+    protected void activityCleanUp() {
+        setLogScrollViewListener(null /* listener */);
+    }
+
     public String testWalking() throws Throwable {
         return runTest(
                 R.string.snsr_step_counter_test_walking,
@@ -323,11 +334,10 @@
         // TODO: with delayed assertions check events of other types are tracked
     }
 
-    private void logUserReportedStep(long timestamp) {
+    private void logUserReportedStep(long timestamp) throws InterruptedException {
         if (!mCheckForMotion) {
             return;
         }
-
         playSound();
         mTimestampsUserReported.add(timestamp);
         getTestLogger().logMessage(R.string.snsr_step_reported, timestamp);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/BaseSensorTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/BaseSensorTestActivity.java
index d1c06cb..0bf9636 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/BaseSensorTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/BaseSensorTestActivity.java
@@ -28,13 +28,14 @@
 import android.content.Context;
 import android.content.Intent;
 import android.hardware.cts.helpers.ActivityResultMultiplexedLatch;
-import android.hardware.cts.helpers.SensorTestStateNotSupportedException;
 import android.media.MediaPlayer;
 import android.opengl.GLSurfaceView;
 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;
@@ -42,8 +43,11 @@
 import android.widget.ScrollView;
 import android.widget.TextView;
 
-import java.security.InvalidParameterException;
-import java.util.concurrent.Semaphore;
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
 
 /**
  * A base Activity that is used to build different methods to execute tests inside CtsVerifier.
@@ -76,10 +80,11 @@
     private final int mLayoutId;
     private final SensorFeaturesDeactivator mSensorFeaturesDeactivator;
 
-    private final Semaphore mSemaphore = new Semaphore(0);
+    private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
     private final SensorTestLogger mTestLogger = new SensorTestLogger();
     private final ActivityResultMultiplexedLatch mActivityResultMultiplexedLatch =
             new ActivityResultMultiplexedLatch();
+    private final ArrayList<CountDownLatch> mWaitForUserLatches = new ArrayList<CountDownLatch>();
 
     private ScrollView mLogScrollView;
     private LinearLayout mLogLayout;
@@ -128,7 +133,13 @@
         mGLSurfaceView = (GLSurfaceView) findViewById(R.id.gl_surface_view);
 
         updateNextButton(false /*enabled*/);
-        new Thread(this).start();
+        mExecutorService.execute(this);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mExecutorService.shutdownNow();
     }
 
     @Override
@@ -149,7 +160,12 @@
 
     @Override
     public void onClick(View target) {
-        mSemaphore.release();
+        synchronized (mWaitForUserLatches) {
+            for (CountDownLatch latch : mWaitForUserLatches) {
+                latch.countDown();
+            }
+            mWaitForUserLatches.clear();
+        }
     }
 
     @Override
@@ -167,40 +183,36 @@
      */
     @Override
     public void run() {
+        long startTimeNs = SystemClock.elapsedRealtimeNanos();
         String testName = getTestClassName();
 
-        // guarantee the proper clean up of tests based on the operations that successfully ran
-        SensorTestDetails testDetails = deactivateSensorFeatures();
-        if (testDetails.getResultCode() == SensorTestDetails.ResultCode.PASS) {
-            // sensor features
-            testDetails = executeActivitySetUp();
-            if (testDetails.getResultCode() == SensorTestDetails.ResultCode.PASS) {
-                // activity set up
-                // TODO: implement execution filters:
-                //      - execute all tests and report results officially
-                //      - execute single test or failed tests only
-                testDetails = executeTests();
-                try {
-                    activityCleanUp();
-                } catch (Throwable e) {
-                    testDetails = new SensorTestDetails(
-                            testName,
-                            SensorTestDetails.ResultCode.FAIL,
-                            "[ActivityCleanUp] " + e.getMessage());
-                }
-                // end activity set up
-            }
-            try {
-                mSensorFeaturesDeactivator.requestToRestoreFeatures();
-            } catch (Throwable e) {
-                testDetails = new SensorTestDetails(
-                        testName,
-                        SensorTestDetails.ResultCode.FAIL,
-                        "[RestoreSensorFeatures] " + e.getMessage());
-            }
-            // end sensor features
+        SensorTestDetails testDetails;
+        try {
+            mSensorFeaturesDeactivator.requestDeactivationOfFeatures();
+            testDetails = new SensorTestDetails(testName, SensorTestDetails.ResultCode.PASS);
+        } catch (Throwable e) {
+            testDetails = new SensorTestDetails(testName, "DeactivateSensorFeatures", e);
         }
+
+        SensorTestDetails.ResultCode resultCode = testDetails.getResultCode();
+        if (resultCode == SensorTestDetails.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 == SensorTestDetails.ResultCode.PASS) {
+            testDetails = executeActivityTests(testName);
+        }
+
+        // we consider all remaining states at this point, because we could have been half way
+        // deactivating features
+        try {
+            mSensorFeaturesDeactivator.requestToRestoreFeatures();
+        } catch (Throwable e) {
+            testDetails = new SensorTestDetails(testName, "RestoreSensorFeatures", e);
+        }
+
         mTestLogger.logTestDetails(testDetails);
+        mTestLogger.logExecutionTime(startTimeNs);
 
         // because we cannot enforce test failures in several devices, set the test UI so the
         // operator can report the result of the test
@@ -210,6 +222,9 @@
     /**
      * 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 {}
@@ -218,6 +233,11 @@
      * 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.
      */
@@ -229,7 +249,7 @@
      *
      * @return A {@link SensorTestDetails} object containing information about the executed tests.
      */
-    protected abstract SensorTestDetails executeTests();
+    protected abstract SensorTestDetails executeTests() throws InterruptedException;
 
     @Override
     public SensorTestLogger getTestLogger() {
@@ -237,11 +257,6 @@
     }
 
     @Deprecated
-    protected void appendText(String text, int textColor) {
-        appendText(text);
-    }
-
-    @Deprecated
     protected void appendText(int resId) {
         mTestLogger.logInstructions(resId);
     }
@@ -268,21 +283,22 @@
      *
      * @param waitMessageResId The action requested to the operator.
      */
-    protected void waitForUser(int waitMessageResId) {
+    protected void waitForUser(int waitMessageResId) throws InterruptedException {
+        CountDownLatch latch = new CountDownLatch(1);
+        synchronized (mWaitForUserLatches) {
+            mWaitForUserLatches.add(latch);
+        }
+
         mTestLogger.logInstructions(waitMessageResId);
         updateNextButton(true);
-        try {
-            mSemaphore.acquire();
-        } catch (InterruptedException e)  {
-            Log.e(LOG_TAG, "Error on waitForUser", e);
-        }
+        latch.await();
         updateNextButton(false);
     }
 
     /**
      * Waits for the operator to acknowledge to begin execution.
      */
-    protected void waitForUserToBegin() {
+    protected void waitForUserToBegin() throws InterruptedException {
         waitForUser(R.string.snsr_wait_to_begin);
     }
 
@@ -290,20 +306,15 @@
      * {@inheritDoc}
      */
     @Override
-    public void waitForUserToContinue() {
+    public void waitForUserToContinue() throws InterruptedException {
         waitForUser(R.string.snsr_wait_for_user);
     }
 
-    @Deprecated
-    protected void waitForUser() {
-        waitForUserToContinue();
-    }
-
     /**
      * {@inheritDoc}
      */
     @Override
-    public int executeActivity(String action) {
+    public int executeActivity(String action) throws InterruptedException {
         return executeActivity(new Intent(action));
     }
 
@@ -311,7 +322,7 @@
      * {@inheritDoc}
      */
     @Override
-    public int executeActivity(Intent intent) {
+    public int executeActivity(Intent intent) throws InterruptedException {
         ActivityResultMultiplexedLatch.Latch latch = mActivityResultMultiplexedLatch.bindThread();
         startActivityForResult(intent, latch.getRequestCode());
         return latch.await();
@@ -352,18 +363,15 @@
     /**
      * Plays a (default) sound as a notification for the operator.
      */
-    protected void playSound() {
+    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);
-        } catch(InterruptedException e) {
-            Log.d(LOG_TAG, "Error on playSound", e);
         } finally {
             player.stop();
         }
@@ -411,10 +419,16 @@
         return mTestClass.getName();
     }
 
+    protected void setLogScrollViewListener(View.OnTouchListener listener) {
+        mLogScrollView.setOnTouchListener(listener);
+    }
+
     private void setTestResult(SensorTestDetails 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();
-        String name = testDetails.getName();
-        switch(testDetails.getResultCode()) {
+        SensorTestDetails.ResultCode resultCode = testDetails.getResultCode();
+        switch(resultCode) {
             case SKIPPED:
                 TestResult.setPassedResult(this, name, summary);
                 break;
@@ -424,48 +438,50 @@
             case FAIL:
                 TestResult.setFailedResult(this, name, summary);
                 break;
+            case INTERRUPTED:
+                // do not set a result, just return so the test can complete
+                break;
+            default:
+                throw new IllegalStateException("Unknown ResultCode: " + resultCode);
         }
     }
 
-    private SensorTestDetails deactivateSensorFeatures() {
-        String testName = getTestClassName();
-        try {
-            mSensorFeaturesDeactivator.requestDeactivationOfFeatures();
-        } catch (Throwable e) {
-            return new SensorTestDetails(
-                    testName,
-                    SensorTestDetails.ResultCode.FAIL,
-                    "[DeactivateSensorFeatures] " + e.getMessage());
-        }
-        return new SensorTestDetails(
-                testName,
-                SensorTestDetails.ResultCode.PASS,
-                null /* summary */);
-    }
-
-    private SensorTestDetails executeActivitySetUp() {
-        String testName = getTestClassName();
+    private SensorTestDetails executeActivityTests(String testName) {
+        SensorTestDetails testDetails;
         try {
             activitySetUp();
-        } catch (SensorTestStateNotSupportedException e) {
-            return new SensorTestDetails(
-                    testName,
-                    SensorTestDetails.ResultCode.SKIPPED,
-                    e.getMessage());
+            testDetails = new SensorTestDetails(testName, SensorTestDetails.ResultCode.PASS);
         } catch (Throwable e) {
-            return new SensorTestDetails(
-                    testName,
-                    SensorTestDetails.ResultCode.FAIL,
-                    "[ActivitySetUp] " + e.getMessage());
+            testDetails = new SensorTestDetails(testName, "ActivitySetUp", e);
         }
-        return new SensorTestDetails(
-                testName,
-                SensorTestDetails.ResultCode.PASS,
-                null /* summary */);
+
+        SensorTestDetails.ResultCode resultCode = testDetails.getResultCode();
+        if (resultCode == SensorTestDetails.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 SensorTestDetails(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 SensorTestDetails(testName, "ActivityCleanUp", e);
+        }
+
+        return testDetails;
     }
 
     private void promptUserToSetResult(SensorTestDetails testDetails) {
-        if (testDetails.getResultCode() == SensorTestDetails.ResultCode.FAIL) {
+        SensorTestDetails.ResultCode resultCode = testDetails.getResultCode();
+        if (resultCode == SensorTestDetails.ResultCode.FAIL) {
             mTestLogger.logInstructions(R.string.snsr_test_complete_with_errors);
             enableTestResultButton(
                     mPassButton,
@@ -475,7 +491,7 @@
                     mFailButton,
                     R.string.fail_button_text,
                     testDetails.cloneAndChangeResultCode(SensorTestDetails.ResultCode.FAIL));
-        } else {
+        } else if (resultCode != SensorTestDetails.ResultCode.INTERRUPTED) {
             mTestLogger.logInstructions(R.string.snsr_test_complete);
             enableTestResultButton(
                     mPassButton,
@@ -548,7 +564,8 @@
         public void logTestDetails(SensorTestDetails testDetails) {
             String name = testDetails.getName();
             String summary = testDetails.getSummary();
-            switch (testDetails.getResultCode()) {
+            SensorTestDetails.ResultCode resultCode = testDetails.getResultCode();
+            switch (resultCode) {
                 case SKIPPED:
                     logTestSkip(name, summary);
                     break;
@@ -558,9 +575,11 @@
                 case FAIL:
                     logTestFail(name, summary);
                     break;
+                case INTERRUPTED:
+                    // do nothing, the test was interrupted so do we
+                    break;
                 default:
-                    throw new InvalidParameterException(
-                            "Invalid SensorTestDetails.ResultCode: " + testDetails.getResultCode());
+                    throw new IllegalStateException("Unknown ResultCode: " + resultCode);
             }
         }
 
@@ -589,6 +608,17 @@
             return mOverallSummaryBuilder.toString();
         }
 
+        void logExecutionTime(long startTimeNs) {
+            if (Thread.currentThread().isInterrupted()) {
+                return;
+            }
+            long executionTimeNs = SystemClock.elapsedRealtimeNanos() - startTimeNs;
+            long executionTimeSec = TimeUnit.NANOSECONDS.toSeconds(executionTimeNs);
+            // TODO: find a way to format times with nanosecond accuracy and longer than 24hrs
+            String formattedElapsedTime = DateUtils.formatElapsedTime(executionTimeSec);
+            logMessage(R.string.snsr_execution_time, formattedElapsedTime);
+        }
+
         private void logTestEnd(int textViewResId, String testSummary) {
             TextAppender textAppender = new TextAppender(textViewResId);
             textAppender.setText(testSummary);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/ISensorTestStateContainer.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/ISensorTestStateContainer.java
index 3ef7e21..2ba74e3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/ISensorTestStateContainer.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/ISensorTestStateContainer.java
@@ -33,7 +33,7 @@
     /**
      * Waits for the operator to acknowledge to continue execution.
      */
-    void waitForUserToContinue();
+    void waitForUserToContinue() throws InterruptedException;
 
     /**
      * @param resId The resource Id to extract.
@@ -55,7 +55,7 @@
      * @param action The action to start the Activity.
      * @return The Activity's result code.
      */
-    int executeActivity(String action);
+    int executeActivity(String action) throws InterruptedException;
 
     /**
      * Starts an Activity and blocks until it completes, then it returns its result back to the
@@ -64,7 +64,7 @@
      * @param intent The intent to start the Activity.
      * @return The Activity's result code.
      */
-    int executeActivity(Intent intent);
+    int executeActivity(Intent intent) throws InterruptedException;
 
     /**
      * @return The {@link ContentResolver} associated with the test.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsTestActivity.java
index 35bff24..16c5fcd 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsTestActivity.java
@@ -37,7 +37,6 @@
 import org.junit.runners.model.InitializationError;
 import org.junit.runners.model.RunnerBuilder;
 
-import android.app.KeyguardManager;
 import android.content.Context;
 import android.hardware.cts.SensorTestCase;
 import android.os.PowerManager;
@@ -67,11 +66,11 @@
     }
 
     @Override
-    protected void activitySetUp() {
-        mScreenManipulator = new SensorTestScreenManipulator(getApplicationContext());
-        mScreenManipulator.initialize(this);
+    protected void activitySetUp() throws InterruptedException {
         PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
         mWakeLock =  powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SensorCtsTests");
+        mScreenManipulator = new SensorTestScreenManipulator(getApplicationContext());
+        mScreenManipulator.initialize(this);
 
         SensorTestLogger logger = getTestLogger();
         logger.logInstructions(R.string.snsr_no_interaction);
@@ -93,7 +92,9 @@
             }
         });
         mScreenManipulator.turnScreenOn();
-        mWakeLock.release();
+        if (mWakeLock.isHeld()) {
+            mWakeLock.release();
+        }
     }
 
     @Override
@@ -101,6 +102,7 @@
         super.onDestroy();
         if (mScreenManipulator != null) {
             mScreenManipulator.releaseScreenOn();
+            mScreenManipulator.close();
         }
     }
 
@@ -154,7 +156,7 @@
             return new JUnit38ClassRunner(sensorTestSuite);
         }
 
-        private boolean hasSuiteMethod(Class testClass) {
+        private boolean hasSuiteMethod(Class<?> testClass) {
             try {
                 testClass.getMethod("suite");
                 return true;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsTestResult.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsTestResult.java
index 851d405..5bbaaf7 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsTestResult.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsTestResult.java
@@ -39,6 +39,8 @@
     private final Context mContext;
     private final TestResult mWrappedTestResult;
 
+    private volatile boolean mInterrupted;
+
     public SensorCtsTestResult(Context context, TestResult testResult) {
         mContext = context;
         mWrappedTestResult = testResult;
@@ -96,12 +98,23 @@
 
     @Override
     public void runProtected(Test test, Protectable protectable) {
-        mWrappedTestResult.runProtected(test, 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 mWrappedTestResult.shouldStop();
+        return mInterrupted || mWrappedTestResult.shouldStop();
     }
 
     @Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsVerifierTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsVerifierTestActivity.java
index 09753cc..a88abd0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsVerifierTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsVerifierTestActivity.java
@@ -19,8 +19,6 @@
 
 import com.android.cts.verifier.sensors.reporting.SensorTestDetails;
 
-import android.hardware.cts.helpers.SensorTestStateNotSupportedException;
-
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
@@ -47,29 +45,16 @@
     }
 
     /**
-     * {@inheritDoc}
-     */
-    protected SensorCtsVerifierTestActivity(
-            Class<? extends SensorCtsVerifierTestActivity> testClass,
-            int layoutId) {
-        super(testClass, layoutId);
-    }
-
-    /**
      * Executes Semi-automated Sensor tests.
      * Execution is driven by this class, and allows discovery of tests using reflection.
      */
     @Override
-    protected SensorTestDetails executeTests() {
+    protected SensorTestDetails executeTests() throws InterruptedException {
         // TODO: use reporting to log individual test results
-        StringBuilder overallTestResults = new StringBuilder();
         for (Method testMethod : findTestMethods()) {
             SensorTestDetails testDetails = executeTest(testMethod);
             getTestLogger().logTestDetails(testDetails);
-            overallTestResults.append(testDetails.toString());
-            overallTestResults.append("\n");
         }
-
         return new SensorTestDetails(
                 getApplicationContext(),
                 getTestClassName(),
@@ -91,34 +76,40 @@
         return testMethods;
     }
 
-    private SensorTestDetails executeTest(Method testMethod) {
+    private SensorTestDetails executeTest(Method testMethod) throws InterruptedException {
         String testMethodName = testMethod.getName();
         String testName = String.format("%s#%s", getTestClassName(), testMethodName);
-        String testSummary;
-        SensorTestDetails.ResultCode testResultCode;
 
+        SensorTestDetails testDetails;
         try {
-            getTestLogger().logTestStart(testMethod.getName());
-            testSummary = (String) testMethod.invoke(this);
-            testResultCode = SensorTestDetails.ResultCode.PASS;
-            ++mTestPassedCounter;
+            getTestLogger().logTestStart(testMethodName);
+            String testSummary = (String) testMethod.invoke(this);
+            testDetails =
+                    new SensorTestDetails(testName, SensorTestDetails.ResultCode.PASS, testSummary);
         } catch (InvocationTargetException e) {
             // get the inner exception, because we use reflection APIs to execute the test
-            Throwable cause = e.getCause();
-            testSummary = cause.getMessage();
-            if (cause instanceof SensorTestStateNotSupportedException) {
-                testResultCode = SensorTestDetails.ResultCode.SKIPPED;
-                ++mTestSkippedCounter;
-            } else {
-                testResultCode = SensorTestDetails.ResultCode.FAIL;
-                ++mTestFailedCounter;
-            }
+            testDetails = new SensorTestDetails(testName, "TestExecution", e.getCause());
         } catch (Throwable e) {
-            testSummary = e.getMessage();
-            testResultCode = SensorTestDetails.ResultCode.FAIL;
-            ++mTestFailedCounter;
+            testDetails = new SensorTestDetails(testName, "TestInfrastructure", e);
         }
 
-        return new SensorTestDetails(testName, testResultCode, testSummary);
+        SensorTestDetails.ResultCode resultCode = testDetails.getResultCode();
+        switch(resultCode) {
+            case PASS:
+                ++mTestPassedCounter;
+                break;
+            case SKIPPED:
+                ++mTestSkippedCounter;
+                break;
+            case INTERRUPTED:
+                throw new InterruptedException();
+            case FAIL:
+                ++mTestFailedCounter;
+                break;
+            default:
+                throw new IllegalStateException("Unknown ResultCode: " + resultCode);
+        }
+
+        return testDetails;
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/helpers/PowerTestHostLink.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/helpers/PowerTestHostLink.java
index 0041aec..ed2fea3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/helpers/PowerTestHostLink.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/helpers/PowerTestHostLink.java
@@ -53,7 +53,7 @@
     public interface HostToDeviceInterface {
         void logTestResult(SensorTestDetails testDetails);
         void raiseError(String testName, String message) throws Exception;
-        void waitForUserAcknowledgement(String message);
+        void waitForUserAcknowledgement(String message) throws InterruptedException;
         void logText(String text);
         void turnScreenOff();
     }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/helpers/SensorFeaturesDeactivator.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/helpers/SensorFeaturesDeactivator.java
index d69d343..36559bd 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/helpers/SensorFeaturesDeactivator.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/helpers/SensorFeaturesDeactivator.java
@@ -23,6 +23,8 @@
 import android.os.Build;
 import android.provider.Settings;
 
+import java.lang.reflect.Field;
+
 /**
  * A helper class that provides a mechanism to:
  * - prompt users to activate/deactivate features that are known to register for sensor data.
@@ -32,13 +34,12 @@
  */
 public class SensorFeaturesDeactivator {
 
-    private boolean mInitialStateCaptured;
-
     private final ISensorTestStateContainer mStateContainer;
 
     private final SensorSettingContainer mAirplaneMode = new AirplaneModeSettingContainer();
     private final SensorSettingContainer mScreenBrightnessMode =
             new ScreenBrightnessModeSettingContainer();
+    private final SensorSettingContainer mAmbientDisplayMode = new AmbientDisplaySettingContainer();
     private final SensorSettingContainer mAutoRotateScreenMode =
             new AutoRotateScreenModeSettingContainer();
     private final SensorSettingContainer mKeepScreenOnMode = new KeepScreenOnModeSettingContainer();
@@ -48,11 +49,12 @@
         mStateContainer = stateContainer;
     }
 
-    public synchronized void requestDeactivationOfFeatures() {
+    public synchronized void requestDeactivationOfFeatures() throws InterruptedException {
         captureInitialState();
 
         mAirplaneMode.requestToSetMode(mStateContainer, true);
         mScreenBrightnessMode.requestToSetMode(mStateContainer, false);
+        mAmbientDisplayMode.requestToSetMode(mStateContainer, false);
         mAutoRotateScreenMode.requestToSetMode(mStateContainer, false);
         mKeepScreenOnMode.requestToSetMode(mStateContainer, false);
         mLocationMode.requestToSetMode(mStateContainer, false);
@@ -63,34 +65,28 @@
         mStateContainer.waitForUserToContinue();
     }
 
-    public synchronized void requestToRestoreFeatures() {
-        if (!isInitialStateCaptured()) {
+    public synchronized void requestToRestoreFeatures() throws InterruptedException {
+        if (Thread.currentThread().isInterrupted()) {
+            // TODO: in the future, if the thread is interrupted, we might need to serialize the
+            //       intermediate state we acquired so we can restore when we have a chance
             return;
         }
 
         mAirplaneMode.requestToResetMode(mStateContainer);
         mScreenBrightnessMode.requestToResetMode(mStateContainer);
+        mAmbientDisplayMode.requestToResetMode(mStateContainer);
         mAutoRotateScreenMode.requestToResetMode(mStateContainer);
         mKeepScreenOnMode.requestToResetMode(mStateContainer);
         mLocationMode.requestToResetMode(mStateContainer);
     }
 
     private void captureInitialState() {
-        if (mInitialStateCaptured) {
-            return;
-        }
-
         mAirplaneMode.captureInitialState();
         mScreenBrightnessMode.captureInitialState();
+        mAmbientDisplayMode.captureInitialState();
         mAutoRotateScreenMode.captureInitialState();
         mLocationMode.captureInitialState();
         mKeepScreenOnMode.captureInitialState();
-
-        mInitialStateCaptured = true;
-    }
-
-    private boolean isInitialStateCaptured() {
-        return mInitialStateCaptured;
     }
 
     private class AirplaneModeSettingContainer extends SensorSettingContainer {
@@ -99,13 +95,15 @@
         }
 
         @Override
-        protected int getSettingMode() {
+        protected int getSettingMode(int defaultValue) {
             ContentResolver contentResolver = mStateContainer.getContentResolver();
             // Settings.System.AIRPLANE_MODE_ON is deprecated in API 17
             if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
-                return Settings.System.getInt(contentResolver, Settings.System.AIRPLANE_MODE_ON, 0);
+                return Settings.System
+                        .getInt(contentResolver, Settings.System.AIRPLANE_MODE_ON, defaultValue);
             } else {
-                return Settings.Global.getInt(contentResolver, Settings.Global.AIRPLANE_MODE_ON, 0);
+                return Settings.Global
+                        .getInt(contentResolver, Settings.Global.AIRPLANE_MODE_ON, defaultValue);
             }
         }
     }
@@ -116,11 +114,42 @@
         }
 
         @Override
-        public int getSettingMode() {
+        public int getSettingMode(int defaultValue) {
             return Settings.System.getInt(
                     mStateContainer.getContentResolver(),
                     Settings.System.SCREEN_BRIGHTNESS_MODE,
-                    Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
+                    defaultValue);
+        }
+    }
+
+    private class AmbientDisplaySettingContainer extends SensorSettingContainer {
+        public AmbientDisplaySettingContainer() {
+            super(Settings.ACTION_DISPLAY_SETTINGS, R.string.snsr_setting_ambient_display);
+        }
+
+        @Override
+        protected int getSettingMode(int defaultValue) {
+            // TODO: replace the use of reflection with Settings.Secure.DOZE_ENABLED when the
+            //       static field is not hidden anymore
+            Class<?> secureSettingsClass = Settings.Secure.class;
+            Field dozeEnabledField;
+            try {
+                dozeEnabledField = secureSettingsClass.getField("DOZE_ENABLED");
+            } catch (NoSuchFieldException e) {
+                return defaultValue;
+            }
+
+            String settingName;
+            try {
+                settingName = (String) dozeEnabledField.get(null /* obj */);
+            } catch (IllegalAccessException e) {
+                return defaultValue;
+            }
+
+            return Settings.Secure.getInt(
+                    mStateContainer.getContentResolver(),
+                    settingName,
+                    defaultValue);
         }
     }
 
@@ -131,11 +160,11 @@
         }
 
         @Override
-        protected int getSettingMode() {
+        protected int getSettingMode(int defaultValue) {
             return Settings.System.getInt(
                     mStateContainer.getContentResolver(),
                     Settings.System.ACCELEROMETER_ROTATION,
-                    0 /* default */);
+                    defaultValue);
         }
     }
 
@@ -146,11 +175,11 @@
         }
 
         @Override
-        protected int getSettingMode() {
+        protected int getSettingMode(int defaultValue) {
             return Settings.Global.getInt(
                     mStateContainer.getContentResolver(),
                     Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
-                    0);
+                    defaultValue);
         }
     }
 
@@ -160,11 +189,11 @@
         }
 
         @Override
-        protected int getSettingMode() {
+        protected int getSettingMode(int defaultValue) {
             return Settings.Secure.getInt(
                     mStateContainer.getContentResolver(),
                     Settings.Secure.LOCATION_MODE,
-                    Settings.Secure.LOCATION_MODE_OFF);
+                    defaultValue);
         }
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/helpers/SensorSettingContainer.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/helpers/SensorSettingContainer.java
index 9a0d7e5..2d44d8d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/helpers/SensorSettingContainer.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/helpers/SensorSettingContainer.java
@@ -24,12 +24,18 @@
  * A helper class for {@link SensorFeaturesDeactivator}. It abstracts the responsibility of handling
  * device settings that affect sensors.
  *
- * This class is not thread safe. It is meant to be used only by {@link SensorFeaturesDeactivator}.
+ * This class is meant to be used only by {@link SensorFeaturesDeactivator}.
+ * To keep things simple, this class synchronizes access to its internal state on public methods.
+ * This approach is fine, because there is no need for concurrent access.
  */
 abstract class SensorSettingContainer {
+    private static final int DEFAULT_SETTING_VALUE = -1;
+
     private final String mAction;
     private final int mSettingNameResId;
 
+    private boolean mInitialized;
+    private boolean mSettingAvailable;
     private boolean mCapturedModeOn;
 
     public SensorSettingContainer(String action, int settingNameResId) {
@@ -37,13 +43,21 @@
         mSettingNameResId = settingNameResId;
     }
 
-    public void captureInitialState() {
+    public synchronized void captureInitialState() {
+        if (mInitialized) {
+            return;
+        }
+        mSettingAvailable = getSettingMode(DEFAULT_SETTING_VALUE) != DEFAULT_SETTING_VALUE;
         mCapturedModeOn = getCurrentSettingMode();
+        mInitialized = true;
     }
 
     public synchronized void requestToSetMode(
             ISensorTestStateContainer stateContainer,
-            boolean modeOn) {
+            boolean modeOn) throws InterruptedException {
+        if (!isSettingAvailable()) {
+            return;
+        }
         trySetMode(stateContainer, modeOn);
         if (getCurrentSettingMode() != modeOn) {
             String message = stateContainer.getString(
@@ -54,11 +68,16 @@
         }
     }
 
-    public synchronized void requestToResetMode(ISensorTestStateContainer stateContainer) {
+    public synchronized void requestToResetMode(ISensorTestStateContainer stateContainer)
+            throws InterruptedException {
+        if (!isSettingAvailable()) {
+            return;
+        }
         trySetMode(stateContainer, mCapturedModeOn);
     }
 
-    private void trySetMode(ISensorTestStateContainer stateContainer, boolean modeOn) {
+    private void trySetMode(ISensorTestStateContainer stateContainer, boolean modeOn)
+            throws InterruptedException {
         BaseSensorTestActivity.SensorTestLogger logger = stateContainer.getTestLogger();
         String settingName = getSettingName(stateContainer);
         if (getCurrentSettingMode() == modeOn) {
@@ -73,12 +92,20 @@
     }
 
     private boolean getCurrentSettingMode() {
-        return getSettingMode() != 0;
+        return getSettingMode(DEFAULT_SETTING_VALUE) != 0;
     }
 
     private String getSettingName(ISensorTestStateContainer stateContainer) {
         return stateContainer.getString(mSettingNameResId);
     }
 
-    protected abstract int getSettingMode();
+    private boolean isSettingAvailable() {
+        if (!mInitialized) {
+            throw new IllegalStateException(
+                    "Object must be initialized first by invoking #captureInitialState.");
+        }
+        return mSettingAvailable;
+    }
+
+    protected abstract int getSettingMode(int defaultValue);
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/helpers/SensorTestScreenManipulator.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/helpers/SensorTestScreenManipulator.java
index 0263975..835ff56 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/helpers/SensorTestScreenManipulator.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/helpers/SensorTestScreenManipulator.java
@@ -85,7 +85,8 @@
      * NOTE: Initialization will bring up an Activity to let the user activate the Device Admin,
      * this method will block until the user completes the operation.
      */
-    public synchronized void initialize(ISensorTestStateContainer stateContainer) {
+    public synchronized void initialize(ISensorTestStateContainer stateContainer)
+            throws InterruptedException {
         if (!isDeviceAdminInitialized()) {
             Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
             intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mComponentName);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/reporting/SensorTestDetails.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/reporting/SensorTestDetails.java
index dcf6c4a..c88187c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/reporting/SensorTestDetails.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/reporting/SensorTestDetails.java
@@ -22,6 +22,7 @@
 import org.junit.runner.Result;
 
 import android.content.Context;
+import android.hardware.cts.helpers.SensorTestStateNotSupportedException;
 
 /**
  * A class that holds the result of a Sensor test execution.
@@ -34,7 +35,12 @@
     public enum ResultCode {
         SKIPPED,
         PASS,
-        FAIL
+        FAIL,
+        INTERRUPTED
+    }
+
+    public SensorTestDetails(String name, ResultCode resultCode) {
+        this(name, resultCode, null /* summary */);
     }
 
     public SensorTestDetails(String name, ResultCode resultCode, String summary) {
@@ -69,6 +75,21 @@
                 result.getFailureCount());
     }
 
+    public SensorTestDetails(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();
+        } else if (cause instanceof SensorTestStateNotSupportedException) {
+            resultCode = ResultCode.SKIPPED;
+        }
+
+        mName = name;
+        mResultCode = resultCode;
+        mSummary = String.format("[%s] %s", tag, cause.getMessage());
+    }
+
     public String getName() {
         return mName;
     }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/streamquality/StreamingVideoActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/streamquality/StreamingVideoActivity.java
index fa233e8..9684d97 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/streamquality/StreamingVideoActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/streamquality/StreamingVideoActivity.java
@@ -119,30 +119,30 @@
         new Stream("H263 Video, AMR Audio", "http_h263_amr",
                 "http://redirector.c.play.google.com/"
                 + "videoplayback?id=271de9756065677e"
-                + "&itag=13&ip=0.0.0.0&ipbits=0&expire=999999999999999999"
-                + "&sparams=ip,ipbits,expire,ip,ipbits,expire,id,itag"
-                + "&signature=372FA4C532AA49D14EAF049BCDA66460EEE161E9"
-                + ".6D8BF096B73B7A68A7032CA8685053CFB498D30A"
+                + "&itag=13&ip=0.0.0.0&ipbits=0&expire=19000000000"
+                + "&sparams=ip,ipbits,expire,id,itag"
+                + "&signature=073A731E2BDF1E05206AC7B9B895C922ABCBA01D"
+                + ".1DDA3F999541D2136E6755F16FC44CA972767169"
                 + "&source=youtube"
-                + "&key=test_key1&user=android-device-test"),
+                + "&key=ik0&user=android-device-test"),
         new Stream("MPEG4 SP Video, AAC Audio", "http_mpeg4_aac",
                 "http://redirector.c.play.google.com/"
                 + "videoplayback?id=271de9756065677e"
-                + "&itag=17&ip=0.0.0.0&ipbits=0&expire=999999999999999999"
-                + "&sparams=ip,ipbits,expire,ip,ipbits,expire,id,itag"
-                + "&signature=3DCD3F79E045F95B6AF661765F046FB0440FF016"
-                + ".06A42661B3AF6BAF046F012549CC9BA34EBC80A9"
+                + "&itag=17&ip=0.0.0.0&ipbits=0&expire=19000000000"
+                + "&sparams=ip,ipbits,expire,id,itag"
+                + "&signature=6B0F8B8A6A7FD9E4CDF123349C2E061ED2020D74"
+                + ".3460FC81D6C8894BA2D241597D2E1D059845F5F0"
                 + "&source=youtube"
-                + "&key=test_key1&user=android-device-test"),
+                + "&key=ik0&user=android-device-test"),
         new Stream("H264 Base Video, AAC Audio", "http_h264_aac",
                 "http://redirector.c.play.google.com/"
                 + "videoplayback?id=271de9756065677e"
-                + "&itag=18&ip=0.0.0.0&ipbits=0&expire=999999999999999999"
-                + "&sparams=ip,ipbits,expire,ip,ipbits,expire,id,itag"
-                + "&signature=1219C2B07AF0638C27916307A6093C0E43CB894E"
-                + ".126B6B916BD57157782738AA7C03E59F21DBC168"
+                + "&itag=18&ip=0.0.0.0&ipbits=0&expire=19000000000"
+                + "&sparams=ip,ipbits,expire,id,itag"
+                + "&signature=75627CD4CEA73D7868CBDE3CE5C4011955164107"
+                + ".1DCFB0EF1372B48DDCFBE69645FE137AC02AF561"
                 + "&source=youtube"
-                + "&key=test_key1&user=android-device-test"),
+                + "&key=ik0&user=android-device-test"),
     };
 
     @Override
diff --git a/build/config.mk b/build/config.mk
index e127e90..931220b 100644
--- a/build/config.mk
+++ b/build/config.mk
@@ -18,3 +18,4 @@
 BUILD_CTS_HOST_JAVA_LIBRARY := cts/build/test_host_java_library.mk
 BUILD_CTS_TARGET_JAVA_LIBRARY := cts/build/test_target_java_library.mk
 BUILD_CTS_UI_JAVA_LIBRARY := cts/build/test_uiautomator.mk
+BUILD_CTS_DEQP_PACKAGE := cts/build/test_deqp_package.mk
diff --git a/build/deqp_dummy_test_list b/build/deqp_dummy_test_list
new file mode 100644
index 0000000..6bf22aa
--- /dev/null
+++ b/build/deqp_dummy_test_list
@@ -0,0 +1,3 @@
+suite:TestSuite
+case:TEST_CASE_NAME
+test:TEST_NAME
diff --git a/build/test_deqp_package.mk b/build/test_deqp_package.mk
new file mode 100644
index 0000000..b07876d
--- /dev/null
+++ b/build/test_deqp_package.mk
@@ -0,0 +1,44 @@
+# Copyright (C) 2012 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.
+
+#
+# Builds dEQP test description XMLs needed by CTS.
+#
+
+CTS_DEQP_CONFIG_PATH := $(call my-dir)
+
+cts_library_xml := $(CTS_TESTCASES_OUT)/com.drawelements.deqp.$(DEQP_API).xml
+
+$(cts_library_xml): MUSTPASS_XML_FILE := external/deqp/android/cts/com.drawelements.deqp.$(DEQP_API).xml
+$(cts_library_xml): PRIVATE_TEST_NAME := $(DEQP_TEST_NAME)
+$(cts_library_xml): PRIVATE_TEST_PACKAGE := com.drawelements.deqp.$(DEQP_API)
+$(cts_library_xml): PRIVATE_DUMMY_CASELIST := $(CTS_DEQP_CONFIG_PATH)/deqp_dummy_test_list
+$(cts_library_xml): $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME))/package.apk external/deqp/android/cts/com.drawelements.deqp.$(DEQP_API).xml $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_XML_GENERATOR)
+	$(hide) echo Generating test description for $(PRIVATE_TEST_NAME)
+	$(hide) mkdir -p $(CTS_TESTCASES_OUT)
+	
+# Query build ABIs by routing a dummy test list through xml generator and parse result
+	$(hide) $(eval supported_abi_attr := $(shell $(CTS_XML_GENERATOR) -t dummyTest \
+										-n dummyName \
+										-p invalid.dummy \
+										-e $(CTS_EXPECTATIONS) \
+										-b $(CTS_UNSUPPORTED_ABIS) \
+										-a $(CTS_TARGET_ARCH) \
+										< $(PRIVATE_DUMMY_CASELIST) \
+										| grep --only-matching -e " abis=\"[^\"]*\""))
+	
+# Patch xml caselist with supported abi
+	$(hide) $(SED_EXTENDED) -e 's:^<Test (.*)/>$$:<Test \1 $(supported_abi_attr) />:' \
+				< $(MUSTPASS_XML_FILE) \
+				> $@
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
index 83187c7..fe8f9ee 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
@@ -30,6 +30,7 @@
 import android.support.test.uiautomator.UiSelector;
 import android.test.InstrumentationTestCase;
 import android.test.MoreAsserts;
+import android.text.format.DateUtils;
 
 import com.android.cts.documentclient.MyActivity.Result;
 
@@ -47,6 +48,8 @@
     private UiDevice mDevice;
     private MyActivity mActivity;
 
+    private static final long TIMEOUT = 10 * DateUtils.SECOND_IN_MILLIS;
+
     @Override
     public void setUp() throws Exception {
         super.setUp();
@@ -54,6 +57,7 @@
         mDevice = UiDevice.getInstance(getInstrumentation());
         mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
                 MyActivity.class, null);
+        mDevice.waitForIdle();
     }
 
     @Override
@@ -78,7 +82,8 @@
         mActivity.startActivityForResult(intent, 42);
 
         // Ensure that we see both of our roots
-        assertTrue("CtsLocal root", new UiObject(new UiSelector().text("CtsLocal")).exists());
+        mDevice.waitForIdle();
+        assertTrue("CtsLocal root", new UiObject(new UiSelector().text("CtsLocal")).waitForExists(TIMEOUT));
         assertTrue("CtsCreate root", new UiObject(new UiSelector().text("CtsCreate")).exists());
         assertFalse("CtsGetContent", new UiObject(new UiSelector().text("CtsGetContent")).exists());
 
@@ -86,8 +91,6 @@
         mDevice.waitForIdle();
         new UiObject(new UiSelector().text("CtsLocal")).click();
 
-        // make sure drawer is expanded?
-
         mDevice.waitForIdle();
         new UiObject(new UiSelector().text("FILE1")).click();
 
@@ -148,6 +151,7 @@
         mDevice.waitForIdle();
         new UiObject(new UiSelector().text("FILE1")).click();
 
+        mDevice.waitForIdle();
         new UiObject(new UiSelector().resourceId("com.android.documentsui:id/container_save")
                 .childSelector(new UiSelector().resourceId("android:id/button1"))).click();
 
@@ -237,16 +241,15 @@
         intent.setType("*/*");
         mActivity.startActivityForResult(intent, 42);
 
-        mDevice.waitForIdle();
-
         // Look around, we should be able to see both DocumentsProviders and
         // other GET_CONTENT sources.
-        assertTrue("CtsLocal root", new UiObject(new UiSelector().text("CtsLocal")).exists());
+        mDevice.waitForIdle();
+        assertTrue("CtsLocal root", new UiObject(new UiSelector().text("CtsLocal")).waitForExists(TIMEOUT));
         assertTrue("CtsCreate root", new UiObject(new UiSelector().text("CtsCreate")).exists());
         assertTrue("CtsGetContent", new UiObject(new UiSelector().text("CtsGetContent")).exists());
 
-        new UiObject(new UiSelector().text("CtsGetContent")).click();
         mDevice.waitForIdle();
+        new UiObject(new UiSelector().text("CtsGetContent")).click();
 
         final Result result = mActivity.getResult();
         assertEquals("ReSuLt", result.data.getAction());
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk
index bc3acaf..8b25f4b 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk
@@ -30,7 +30,7 @@
 LOCAL_ASSET_DIR := $(LOCAL_PATH)/assets
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
-LOCAL_AAPT_FLAGS := --version-code 100 --version-name OneHundred --replace-version -c mdpi
+LOCAL_AAPT_FLAGS := --version-code 100 --version-name OneHundred --replace-version -c mdpi -c hdpi -c xhdpi -c xxhdpi
 
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_DEX_PREOPT := false
@@ -53,7 +53,7 @@
 LOCAL_PACKAGE_SPLITS := v7
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
-LOCAL_AAPT_FLAGS := --version-code 101 --version-name OneHundredOne --replace-version -c mdpi
+LOCAL_AAPT_FLAGS := --version-code 101 --version-name OneHundredOne --replace-version -c mdpi -c hdpi -c xhdpi -c xxhdpi
 
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_DEX_PREOPT := false
@@ -76,7 +76,7 @@
 LOCAL_PACKAGE_SPLITS := v7
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
-LOCAL_AAPT_FLAGS := --version-code 100 --version-name OneHundred --replace-version -c mdpi
+LOCAL_AAPT_FLAGS := --version-code 100 --version-name OneHundred --replace-version -c mdpi -c hdpi -c xhdpi -c xxhdpi
 
 LOCAL_PROGUARD_ENABLED := disabled
 LOCAL_DEX_PREOPT := false
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
index 9965f60..e93f6c3 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_ASSET_DIR := $(LOCAL_PATH)/assets
 
 LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
-LOCAL_AAPT_FLAGS := --version-code 100 --version-name OneHundred --replace-version -c mdpi
+LOCAL_AAPT_FLAGS := --version-code 100 --version-name OneHundred --replace-version -c mdpi -c hdpi -c xhdpi -c xxhdpi
 
 LOCAL_MODULE_TAGS := tests
 
diff --git a/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/IntentReceiverActivity.java b/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/IntentReceiverActivity.java
index 17dc3f1..59f0752 100644
--- a/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/IntentReceiverActivity.java
+++ b/hostsidetests/devicepolicy/app/IntentReceiver/src/com/android/cts/intent/receiver/IntentReceiverActivity.java
@@ -22,12 +22,11 @@
 import android.util.Log;
 
 import java.io.BufferedReader;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.IOException;
 import java.io.OutputStreamWriter;
 
-
 /**
  * Class to receive intents sent across profile boundaries, and read/write to content uri specified
  * in these intents to test cross-profile content uris.
diff --git a/hostsidetests/devicepolicy/app/IntentSender/Android.mk b/hostsidetests/devicepolicy/app/IntentSender/Android.mk
new file mode 100644
index 0000000..e45ec31
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/IntentSender/Android.mk
@@ -0,0 +1,33 @@
+# 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)
+
+LOCAL_PACKAGE_NAME := CtsIntentSenderApp
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/IntentSender/AndroidManifest.xml b/hostsidetests/devicepolicy/app/IntentSender/AndroidManifest.xml
new file mode 100644
index 0000000..070ef40
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/IntentSender/AndroidManifest.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.intent.sender">
+
+    <uses-sdk android:minSdkVersion="19" />
+
+    <permission
+        android:name="com.android.cts.intent.sender.permission.SAMPLE"
+        android:label="Sample Permission" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+
+        <activity android:name=".IntentSenderActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+            </intent-filter>
+        </activity>
+
+        <provider
+            android:name="android.support.v4.content.FileProvider"
+            android:authorities="com.android.cts.intent.sender.fileprovider"
+            android:grantUriPermissions="true"
+            android:exported="false">
+            <meta-data
+                android:name="android.support.FILE_PROVIDER_PATHS"
+                android:resource="@xml/filepaths" />
+        </provider>
+
+        <provider
+            android:name=".BasicContentProvider"
+            android:authorities="com.android.cts.intent.sender.provider"
+            android:grantUriPermissions="true"
+            android:exported="true"
+            android:permission="com.android.cts.intent.sender.permission.SAMPLE" />
+
+    </application>
+
+    <instrumentation
+        android:name="android.test.InstrumentationTestRunner"
+        android:targetPackage="com.android.cts.intent.sender"
+        android:label="Intent Sender CTS Tests" />
+
+</manifest>
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/res/xml/filepaths.xml b/hostsidetests/devicepolicy/app/IntentSender/res/xml/filepaths.xml
similarity index 100%
rename from hostsidetests/devicepolicy/app/ManagedProfile/res/xml/filepaths.xml
rename to hostsidetests/devicepolicy/app/IntentSender/res/xml/filepaths.xml
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/BasicContentProvider.java b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/BasicContentProvider.java
similarity index 96%
rename from hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/BasicContentProvider.java
rename to hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/BasicContentProvider.java
index f91d404..183ab9f 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/BasicContentProvider.java
+++ b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/BasicContentProvider.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.cts.managedprofile.crossprofilecontent;
+package com.android.cts.intent.sender;
 
 import android.content.ContentProvider;
 import android.content.ContentValues;
@@ -69,4 +69,3 @@
                 new File("/dev/null"), ParcelFileDescriptor.MODE_READ_ONLY);
     }
 }
-
diff --git a/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/IntentSenderActivity.java b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/IntentSenderActivity.java
new file mode 100644
index 0000000..00fa6b7
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/IntentSenderActivity.java
@@ -0,0 +1,55 @@
+/*
+ * 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 com.android.cts.intent.sender;
+
+import android.app.Activity;
+import android.content.Intent;
+
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.TimeUnit;
+
+public class IntentSenderActivity extends Activity {
+
+    private final SynchronousQueue<Result> mResult = new SynchronousQueue<>();
+
+    public static class Result {
+        public final int resultCode;
+        public final Intent data;
+
+        public Result(int resultCode, Intent data) {
+            this.resultCode = resultCode;
+            this.data = data;
+        }
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (resultCode == Activity.RESULT_OK) {
+            try {
+                mResult.offer(new Result(resultCode, data), 5, TimeUnit.SECONDS);
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    public Intent getResult(Intent intent) throws Exception {
+        startActivityForResult(intent, 42);
+        final Result result = mResult.poll(30, TimeUnit.SECONDS);
+        return (result != null) ? result.data : null;
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/CrossProfileContentTest.java b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/IntentSenderTest.java
similarity index 76%
rename from hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/CrossProfileContentTest.java
rename to hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/IntentSenderTest.java
index 85e7d1b..47de0da 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/CrossProfileContentTest.java
+++ b/hostsidetests/devicepolicy/app/IntentSender/src/com/android/cts/intent/sender/IntentSenderTest.java
@@ -13,30 +13,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.cts.managedprofile.crossprofilecontent;
 
-import static com.android.cts.managedprofile.BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT;
+package com.android.cts.intent.sender;
 
-import android.app.admin.DevicePolicyManager;
 import android.content.ClipData;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.net.Uri;
 import android.support.v4.content.FileProvider;
-import android.test.ActivityInstrumentationTestCase2;
+import android.test.InstrumentationTestCase;
 import android.util.Log;
 
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileWriter;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.IOException;
 
-public class CrossProfileContentTest extends
-        ActivityInstrumentationTestCase2<IntentSenderActivity> {
+public class IntentSenderTest extends InstrumentationTestCase {
 
     private static final String MESSAGE = "Sample Message";
 
@@ -49,35 +45,20 @@
 
     private static final String TAG = "CrossProfileContentTest";
 
-    private static final String BASIC_CONTENT_PROVIDER_AUTHORITY =
-            "com.android.cts.managedprofile.basiccontentProvider";
-
-
-    private DevicePolicyManager mDpm;
-
     private Context mContext;
-
-    public CrossProfileContentTest() {
-        super(IntentSenderActivity.class);
-    }
+    private IntentSenderActivity mActivity;
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
         mContext = getInstrumentation().getTargetContext();
-        mDpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(ACTION_READ_FROM_URI);
-        intentFilter.addAction(ACTION_WRITE_TO_URI);
-        intentFilter.addAction(ACTION_TAKE_PERSISTABLE_URI_PERMISSION);
-        mDpm.addCrossProfileIntentFilter(ADMIN_RECEIVER_COMPONENT, intentFilter,
-                DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED);
+        mActivity = launchActivity(mContext.getPackageName(), IntentSenderActivity.class, null);
     }
 
     @Override
-    protected void tearDown() throws Exception {
-        mDpm.clearCrossProfileIntentFilters(ADMIN_RECEIVER_COMPONENT);
+    public void tearDown() throws Exception {
         super.tearDown();
+        mActivity.finish();
     }
 
     /**
@@ -85,14 +66,15 @@
      * This intent will have, in the ClipData, a uri whose associated file stores a message.
      * The receiver will read the message from the uri, and put it inside the result intent.
      */
-    public void testReceiverCanRead() {
+    public void testReceiverCanRead() throws Exception {
         Uri uri = getUriWithTextInFile("reading_test", MESSAGE);
         assertTrue(uri != null);
         Intent intent = new Intent(ACTION_READ_FROM_URI);
         intent.setClipData(ClipData.newRawUri("", uri));
         intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-        Intent result = getActivity().getResultForIntent(intent);
-        assertTrue(result != null);
+
+        final Intent result = mActivity.getResult(intent);
+        assertNotNull(result);
         assertEquals(MESSAGE, result.getStringExtra("extra_response"));
     }
 
@@ -102,7 +84,7 @@
      * The receiver will read the message from the extra, and write it to the uri in
      * the ClipData.
      */
-    public void testReceiverCanWrite() {
+    public void testReceiverCanWrite() throws Exception {
         // It's the receiver of the intent that should write to the uri, not us. So, for now, we
         // write an empty string.
         Uri uri = getUriWithTextInFile("writing_test", "");
@@ -112,19 +94,21 @@
         intent.putExtra("extra_message", MESSAGE);
         intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
                 | Intent.FLAG_GRANT_READ_URI_PERMISSION);
-        getActivity().getResultForIntent(intent);
+
+        mActivity.getResult(intent);
         assertEquals(MESSAGE, getFirstLineFromUri(uri));
     }
 
-    public void testPersistablePermission() {
+    public void testPersistablePermission() throws Exception {
         Uri uri = getUriWithTextInFile("persistable_test", MESSAGE);
         grantPersistableReadPermission(uri);
 
         // Now checking if the receiver can read this uri, without re-granting the read permission.
         Intent intent = new Intent(ACTION_READ_FROM_URI);
         intent.setClipData(ClipData.newRawUri("", uri));
-        Intent result = getActivity().getResultForIntent(intent);
-        assertTrue(result != null);
+
+        final Intent result = mActivity.getResult(intent);
+        assertNotNull(result);
         assertEquals(MESSAGE, result.getStringExtra("extra_response"));
     }
 
@@ -138,7 +122,7 @@
      * uriNotGranted), to enforce that even if an app has permission to one uri of a
      * ContentProvider, it still cannot access a uri it does not have access to.
      */
-    public void testAppPermissionsDontWorkAcrossProfiles() {
+    public void testAppPermissionsDontWorkAcrossProfiles() throws Exception {
         // The FileProvider does not allow to use app permissions. So we need to use another
         // ContentProvider.
         Uri uriGranted = getBasicContentProviderUri("uri_granted");
@@ -152,19 +136,41 @@
         Intent notGrant = new Intent(ACTION_READ_FROM_URI);
         notGrant.setClipData(ClipData.newRawUri("", uriNotGranted));
 
-        Intent result = getActivity().getResultForIntent(notGrant);
-        assertTrue(result != null);
+        final Intent result = mActivity.getResult(notGrant);
+        assertNotNull(result);
         // The receiver did not have permission to read the uri. So it should have caught a security
         // exception.
         assertTrue(result.getBooleanExtra("extra_caught_security_exception", false));
     }
 
-    private void grantPersistableReadPermission(Uri uri) {
+    /**
+     * Ensure that sender is only able to send data that it has access to.
+     */
+    public void testSecurity() throws Exception {
+        // Pick a URI that neither of us have access to; it doens't matter if
+        // its missing, since we expect a SE before a FNFE.
+        final Uri uri = Uri.parse("content://media/external/images/media/10240");
+        final Intent intent = new Intent(ACTION_READ_FROM_URI);
+        intent.setClipData(ClipData.newRawUri("", uri));
+        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+        // We're expecting to run into a security exception
+        final Intent result = mActivity.getResult(intent);
+        if (result == null) {
+            // This is fine; probably of a SecurityException when off in the
+            // system somewhere.
+        } else {
+            // But if we somehow came through, make sure they threw.
+            assertTrue(result.getBooleanExtra("extra_caught_security_exception", false));
+        }
+    }
+
+    private void grantPersistableReadPermission(Uri uri) throws Exception {
         Intent grantPersistable = new Intent(ACTION_TAKE_PERSISTABLE_URI_PERMISSION);
         grantPersistable.setClipData(ClipData.newRawUri("", uri));
         grantPersistable.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
                 | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
-        getActivity().getResultForIntent(grantPersistable);
+        mActivity.getResult(grantPersistable);
     }
 
     private Uri getBasicContentProviderUri(String path) {
@@ -172,7 +178,7 @@
         // granting these uris to other apps, or these apps from trying to access these uris.
         return new Uri.Builder()
                 .scheme(ContentResolver.SCHEME_CONTENT)
-                .authority(BASIC_CONTENT_PROVIDER_AUTHORITY)
+                .authority("com.android.cts.intent.sender.provider")
                 .path(path)
                 .build();
     }
@@ -191,7 +197,7 @@
             Log.e(TAG, "Could not create file " + filename + " with text " + text);
             return null;
         }
-        return FileProvider.getUriForFile(mContext, "com.android.cts.managedprofile.fileprovider",
+        return FileProvider.getUriForFile(mContext, "com.android.cts.intent.sender.fileprovider",
                 file);
     }
 
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
index 56b3671..008ed38 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
@@ -19,9 +19,6 @@
 
     <uses-sdk android:minSdkVersion="20"/>
 
-    <permission android:name="com.android.cts.managedprofile.permission.SAMPLE"
-                android:label="Sample Permission"/>
-
     <application>
         <uses-library android:name="android.test.runner" />
         <receiver
@@ -65,11 +62,6 @@
                 <action android:name="com.android.cts.managedprofile.ACTION_TEST_ALL_ACTIVITY" />
             </intent-filter>
         </activity>
-        <activity android:name=".crossprofilecontent.IntentSenderActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-            </intent-filter>
-        </activity>
         <activity android:name=".UserRestrictionActivity" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -77,22 +69,6 @@
             </intent-filter>
         </activity>
         <activity android:name=".TestActivity" />
-        <provider
-            android:name="android.support.v4.content.FileProvider"
-            android:authorities="com.android.cts.managedprofile.fileprovider"
-            android:grantUriPermissions="true"
-            android:exported="false">
-            <meta-data
-                android:name="android.support.FILE_PROVIDER_PATHS"
-                android:resource="@xml/filepaths" />
-        </provider>
-        <provider
-            android:name="com.android.cts.managedprofile.crossprofilecontent.BasicContentProvider"
-            android:authorities="com.android.cts.managedprofile.basiccontentProvider"
-            android:grantUriPermissions="true"
-            android:exported="true"
-            android:permission="com.android.cts.managedprofile.permission.SAMPLE"
-            />
     </application>
 
     <instrumentation android:name="android.test.InstrumentationTestRunner"
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/AllUsersActivity.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/AllUsersActivity.java
similarity index 100%
rename from hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/AllUsersActivity.java
rename to hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/AllUsersActivity.java
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/ComponentDisablingActivity.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ComponentDisablingActivity.java
similarity index 100%
rename from hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/ComponentDisablingActivity.java
rename to hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ComponentDisablingActivity.java
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileUtils.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileUtils.java
new file mode 100644
index 0000000..9615991
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileUtils.java
@@ -0,0 +1,65 @@
+/*
+ * 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 com.android.cts.managedprofile;
+
+import static com.android.cts.managedprofile.BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.test.AndroidTestCase;
+
+public class CrossProfileUtils extends AndroidTestCase {
+    private static final String ACTION_READ_FROM_URI = "com.android.cts.action.READ_FROM_URI";
+
+    private static final String ACTION_WRITE_TO_URI = "com.android.cts.action.WRITE_TO_URI";
+
+    private static final String ACTION_TAKE_PERSISTABLE_URI_PERMISSION =
+            "com.android.cts.action.TAKE_PERSISTABLE_URI_PERMISSION";
+
+    public void addParentCanAccessManagedFilters() {
+        removeAllFilters();
+
+        final DevicePolicyManager dpm = (DevicePolicyManager) getContext().getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(ACTION_READ_FROM_URI);
+        intentFilter.addAction(ACTION_WRITE_TO_URI);
+        intentFilter.addAction(ACTION_TAKE_PERSISTABLE_URI_PERMISSION);
+        dpm.addCrossProfileIntentFilter(ADMIN_RECEIVER_COMPONENT, intentFilter,
+                DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED);
+    }
+
+    public void addManagedCanAccessParentFilters() {
+        removeAllFilters();
+
+        final DevicePolicyManager dpm = (DevicePolicyManager) getContext().getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(ACTION_READ_FROM_URI);
+        intentFilter.addAction(ACTION_WRITE_TO_URI);
+        intentFilter.addAction(ACTION_TAKE_PERSISTABLE_URI_PERMISSION);
+        dpm.addCrossProfileIntentFilter(ADMIN_RECEIVER_COMPONENT, intentFilter,
+                DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT);
+    }
+
+    public void removeAllFilters() {
+        final DevicePolicyManager dpm = (DevicePolicyManager) getContext().getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+        dpm.clearCrossProfileIntentFilters(ADMIN_RECEIVER_COMPONENT);
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/ManagedProfileActivity.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ManagedProfileActivity.java
similarity index 100%
rename from hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/ManagedProfileActivity.java
rename to hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ManagedProfileActivity.java
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/ManagedProfileTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ManagedProfileTest.java
similarity index 100%
rename from hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/ManagedProfileTest.java
rename to hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ManagedProfileTest.java
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/PrimaryUserActivity.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserActivity.java
similarity index 99%
rename from hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/PrimaryUserActivity.java
rename to hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserActivity.java
index 35f70be..b0e84ae 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/PrimaryUserActivity.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserActivity.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.cts.managedprofile;
 
 import android.app.Activity;
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/PrimaryUserFilterSetterActivity.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserFilterSetterActivity.java
similarity index 100%
rename from hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/PrimaryUserFilterSetterActivity.java
rename to hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserFilterSetterActivity.java
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/PrimaryUserTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserTest.java
similarity index 99%
rename from hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/PrimaryUserTest.java
rename to hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserTest.java
index 7098d9e..40ff6c5 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/PrimaryUserTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PrimaryUserTest.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.cts.managedprofile;
 
 import android.app.admin.DevicePolicyManager;
@@ -55,7 +56,7 @@
     public void testAddCrossProfileIntentFilter_all() {
         assertEquals(2, mPackageManager.queryIntentActivities(
                 new Intent(AllUsersActivity.ACTION), /* flags = */ 0).size());
-        
+
         // If we used startActivity(), the user would have a disambiguation dialog presented which
         // requires human intervention, so we won't be testing like that
     }
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/TestActivity.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/TestActivity.java
similarity index 100%
rename from hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofileintentfilters/TestActivity.java
rename to hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/TestActivity.java
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/IntentSenderActivity.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/IntentSenderActivity.java
deleted file mode 100644
index e4c8ddf..0000000
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/crossprofilecontent/IntentSenderActivity.java
+++ /dev/null
@@ -1,52 +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 com.android.cts.managedprofile.crossprofilecontent;
-
-import static com.android.cts.managedprofile.BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.util.Log;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-public class IntentSenderActivity extends Activity {
-
-    private CountDownLatch mLatch;
-
-    private static final int WAIT_FOR_RESPONSE_TIMEOUT_SECONDS = 5;
-
-    private Intent mResult;
-
-    Intent getResultForIntent(Intent intent) {
-        mLatch = new CountDownLatch(1);
-        mResult = null;
-        startActivityForResult(intent, 0);
-        try {
-            mLatch.await(WAIT_FOR_RESPONSE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
-        } catch (InterruptedException e) {
-        }
-        return mResult;
-    }
-
-    @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent result) {
-        if (resultCode == Activity.RESULT_OK) {
-            mResult = result;
-        }
-        mLatch.countDown();
-    }
-}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 15c7725..544ddff 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -17,6 +17,7 @@
 package com.android.cts.devicepolicy;
 
 import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.cts.util.AbiUtils;
 import com.android.ddmlib.Log.LogLevel;
 import com.android.ddmlib.testrunner.InstrumentationResultParser;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
@@ -26,11 +27,13 @@
 import com.android.ddmlib.testrunner.TestRunResult;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.result.CollectingTestListener;
 import com.android.tradefed.testtype.DeviceTestCase;
 import com.android.tradefed.testtype.IBuildReceiver;
 
+import java.io.File;
 import java.io.FileNotFoundException;
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -74,6 +77,21 @@
                 installResult);
     }
 
+    protected void installAppAsUser(String appFileName, int userId) throws FileNotFoundException,
+            DeviceNotAvailableException {
+        final ITestDevice device = getDevice();
+
+        final File apk = mCtsBuild.getTestApp(appFileName);
+        final String remotePath = "/data/local/tmp/" + apk.getName();
+        if (!device.pushFile(apk, remotePath)) {
+            throw new IllegalStateException("Failed to push " + apk);
+        }
+
+        final String result = device.executeShellCommand(
+                "pm install --user " + userId + " " + remotePath);
+        assertTrue(result, result.contains("\nSuccess"));
+    }
+
     /** Initializes the user with the given id. This is required so that apps can run on it. */
     protected void startUser(int userId) throws DeviceNotAvailableException {
         String command = "am start-user " + userId;
@@ -135,7 +153,17 @@
     protected boolean runDeviceTestsAsUser(
             String pkgName, @Nullable String testClassName, int userId)
             throws DeviceNotAvailableException {
-        return runDeviceTests(pkgName, testClassName, null /*testMethodName*/, userId);
+        return runDeviceTestsAsUser(pkgName, testClassName, null, userId);
+    }
+
+    /** Returns true if the specified tests passed. Tests are run as given user. */
+    protected boolean runDeviceTestsAsUser(
+            String pkgName, @Nullable String testClassName, String testMethodName, int userId)
+            throws DeviceNotAvailableException {
+        if (testClassName.startsWith(".")) {
+            testClassName = pkgName + testClassName;
+        }
+        return runDeviceTests(pkgName, testClassName, testMethodName, userId);
     }
 
     private boolean runDeviceTests(String pkgName, @Nullable String testClassName,
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 88a3b70..6ece85c 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -28,6 +28,9 @@
     private static final String MANAGED_PROFILE_PKG = "com.android.cts.managedprofile";
     private static final String MANAGED_PROFILE_APK = "CtsManagedProfileApp.apk";
 
+    private static final String INTENT_SENDER_PKG = "com.android.cts.intent.sender";
+    private static final String INTENT_SENDER_APK = "CtsIntentSenderApp.apk";
+
     private static final String INTENT_RECEIVER_PKG = "com.android.cts.intent.receiver";
     private static final String INTENT_RECEIVER_APK = "CtsIntentReceiverApp.apk";
 
@@ -110,16 +113,30 @@
         if (!mHasFeature) {
             return;
         }
+
         try {
-            installApp(INTENT_RECEIVER_APK);
+            getDevice().uninstallPackage(INTENT_SENDER_PKG);
+            getDevice().uninstallPackage(INTENT_RECEIVER_PKG);
+            installAppAsUser(INTENT_SENDER_APK, 0);
+            installAppAsUser(INTENT_RECEIVER_APK, mUserId);
 
-            String command = "pm uninstall --user " + mUserId + " " + INTENT_RECEIVER_PKG;
-            CLog.logAndDisplay(LogLevel.INFO, "Output for command " + command + ": "
-                    + getDevice().executeShellCommand(command));
+            // Test from parent to managed
+            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
+                    "addManagedCanAccessParentFilters", mUserId));
+            assertTrue(runDeviceTestsAsUser(INTENT_SENDER_PKG, ".IntentSenderTest", 0));
 
-            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG,
-                    MANAGED_PROFILE_PKG + ".crossprofilecontent.CrossProfileContentTest", mUserId));
+            getDevice().uninstallPackage(INTENT_SENDER_PKG);
+            getDevice().uninstallPackage(INTENT_RECEIVER_PKG);
+            installAppAsUser(INTENT_SENDER_APK, mUserId);
+            installAppAsUser(INTENT_RECEIVER_APK, 0);
+
+            // Test from managed to parent
+            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileUtils",
+                    "addParentCanAccessManagedFilters", mUserId));
+            assertTrue(runDeviceTestsAsUser(INTENT_SENDER_PKG, ".IntentSenderTest", mUserId));
+
         } finally {
+            getDevice().uninstallPackage(INTENT_SENDER_PKG);
             getDevice().uninstallPackage(INTENT_RECEIVER_PKG);
         }
     }
diff --git a/hostsidetests/jdwpsecurity/Android.mk b/hostsidetests/jdwpsecurity/Android.mk
new file mode 100644
index 0000000..561d346
--- /dev/null
+++ b/hostsidetests/jdwpsecurity/Android.mk
@@ -0,0 +1,32 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE_TAGS := optional
+
+# Must match the package name in CtsTestCaseList.mk
+LOCAL_MODULE := CtsJdwpSecurityHostTestCases
+
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+
+LOCAL_CTS_TEST_PACKAGE := android.host.jdwpsecurity
+
+include $(BUILD_CTS_HOST_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/jdwpsecurity/app/Android.mk b/hostsidetests/jdwpsecurity/app/Android.mk
new file mode 100644
index 0000000..13b5be4
--- /dev/null
+++ b/hostsidetests/jdwpsecurity/app/Android.mk
@@ -0,0 +1,30 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := CtsJdwpApp
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+include $(BUILD_JAVA_LIBRARY)
+
+# Copy the built module to the cts dir
+cts_library_jar := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).jar
+$(cts_library_jar): $(LOCAL_BUILT_MODULE)
+	$(copy-file-to-target)
+
+# Have the module name depend on the cts files; so the cts files get generated when you run mm/mmm/mma/mmma.
+$(my_register_name) : $(cts_library_jar)
+
diff --git a/hostsidetests/jdwpsecurity/app/src/com/android/cts/jdwpsecurity/JdwpTest.java b/hostsidetests/jdwpsecurity/app/src/com/android/cts/jdwpsecurity/JdwpTest.java
new file mode 100644
index 0000000..f2e5980
--- /dev/null
+++ b/hostsidetests/jdwpsecurity/app/src/com/android/cts/jdwpsecurity/JdwpTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.jdwpsecurity;
+
+public class JdwpTest {
+    private static final long LOOP_TIMEOUT_MS = 60 * 1000;
+
+    public static void main(String[] args) throws Exception {
+        // Print pid so the test knows who we are.
+        int pid = android.os.Process.myPid();
+        System.out.println(pid);
+
+        // Loop to keep alive so the host test has the time to check whether we have a JDWP
+        // connection.
+        // Note: we use a timeout to avoid indefinite loop in case something wrong happens
+        // with the test harness.
+        long start = System.currentTimeMillis();
+        while(getElapsedTime(start) < LOOP_TIMEOUT_MS) {
+            Thread.sleep(100);
+        }
+    }
+
+    private static long getElapsedTime(long start) {
+        return System.currentTimeMillis() - start;
+    }
+}
diff --git a/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java b/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java
new file mode 100644
index 0000000..8e276ed
--- /dev/null
+++ b/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java
@@ -0,0 +1,284 @@
+/*
+ * 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.jdwpsecurity.cts;
+
+import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.ArrayUtil;
+import com.android.tradefed.util.RunUtil;
+
+import java.io.BufferedReader;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Test to check non-zygote apps do not have an active JDWP connection.
+ */
+public class JdwpSecurityHostTest extends DeviceTestCase implements IBuildReceiver {
+
+    private static final String DEVICE_LOCATION = "/data/local/tmp/jdwpsecurity";
+    private static final String DEVICE_SCRIPT_FILENAME = "jdwptest";
+    private static final String DEVICE_JAR_FILENAME = "CtsJdwpApp.jar";
+    private static final String JAR_MAIN_CLASS_NAME = "com.android.cts.jdwpsecurity.JdwpTest";
+
+    private CtsBuildHelper mCtsBuild;
+
+    private static String getDeviceScriptFilepath() {
+        return DEVICE_LOCATION + File.separator + DEVICE_SCRIPT_FILENAME;
+    }
+
+    private static String getDeviceJarFilepath() {
+        return DEVICE_LOCATION + File.separator + DEVICE_JAR_FILENAME;
+    }
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // Create test directory on the device.
+        createRemoteDir(DEVICE_LOCATION);
+
+        // Also create the dalvik-cache directory. It needs to exist before the runtime starts.
+        createRemoteDir(DEVICE_LOCATION + File.separator + "dalvik-cache");
+
+        // Create and push script on the device.
+        File tempFile = createScriptTempFile();
+        try {
+            boolean success = getDevice().pushFile(tempFile, getDeviceScriptFilepath());
+            assertTrue("Failed to push script to " + getDeviceScriptFilepath(), success);
+        } finally {
+            if (tempFile != null) {
+                tempFile.delete();
+            }
+        }
+
+        // Make the script executable.
+        getDevice().executeShellCommand("chmod 755 " + getDeviceScriptFilepath());
+
+        // Push jar file.
+        File jarFile = mCtsBuild.getTestApp(DEVICE_JAR_FILENAME);
+        boolean success = getDevice().pushFile(jarFile, getDeviceJarFilepath());
+        assertTrue("Failed to push jar file to " + getDeviceScriptFilepath(), success);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        // Delete the whole test directory on the device.
+        getDevice().executeShellCommand(String.format("rm -r %s", DEVICE_LOCATION));
+
+        super.tearDown();
+    }
+
+    /**
+     * Tests a non-zygote app does not have a JDWP connection, thus not being
+     * debuggable.
+     *
+     * Runs a script executing a Java app (jar file) with app_process,
+     * without forking from zygote. Then checks its pid is not returned
+     * by 'adb jdwp', meaning it has no JDWP connection and cannot be
+     * debugged.
+     *
+     * @throws Exception
+     */
+    public void testNonZygoteProgramIsNotDebuggable() throws Exception {
+        String scriptFilepath = getDeviceScriptFilepath();
+        Process scriptProcess = null;
+        String scriptPid = null;
+        List<String> activeJdwpPids = null;
+        try {
+            // Run the script on the background so it's running when we collect the list of
+            // pids with a JDWP connection using 'adb jdwp'.
+            // command.
+            scriptProcess = runScriptInBackground(scriptFilepath);
+
+            // On startup, the script will print its pid on its output.
+            scriptPid = readScriptPid(scriptProcess);
+
+            // Collect the list of pids with a JDWP connection.
+            activeJdwpPids = getJdwpPids();
+        } finally {
+            // Stop the script.
+            if (scriptProcess != null) {
+                scriptProcess.destroy();
+            }
+        }
+
+        assertNotNull("Failed to get script pid", scriptPid);
+        assertNotNull("Failed to get active JDWP pids", activeJdwpPids);
+        assertFalse("Test app should not have an active JDWP connection" +
+                " (pid " + scriptPid + " is returned by 'adb jdwp')",
+                activeJdwpPids.contains(scriptPid));
+    }
+
+    private Process runScriptInBackground(String scriptFilepath) throws IOException {
+        String[] shellScriptCommand = buildAdbCommand("shell", scriptFilepath);
+        return RunUtil.getDefault().runCmdInBackground(shellScriptCommand);
+    }
+
+    private String readScriptPid(Process scriptProcess) throws IOException {
+        BufferedReader br = null;
+        try {
+            br = new BufferedReader(new InputStreamReader(scriptProcess.getInputStream()));
+            // We only expect to read one line containing the pid.
+            return br.readLine();
+        } finally {
+            if (br != null) {
+                br.close();
+            }
+        }
+    }
+
+    private List<String> getJdwpPids() throws Exception {
+        return new AdbJdwpOutputReader().listPidsWithAdbJdwp();
+    }
+
+    /**
+     * Creates the script file on the host so it can be pushed onto the device.
+     *
+     * @return the script file
+     * @throws IOException
+     */
+    private static File createScriptTempFile() throws IOException {
+        File tempFile = File.createTempFile("jdwptest", ".tmp");
+
+        PrintWriter pw = null;
+        try {
+            pw = new PrintWriter(tempFile);
+
+            // We need a dalvik-cache in /data/local/tmp so we have read-write access.
+            // Note: this will cause the runtime to optimize the DEX file (contained in
+            // the jar file) before executing it.
+            pw.println(String.format("export ANDROID_DATA=%s", DEVICE_LOCATION));
+            pw.println(String.format("export CLASSPATH=%s", getDeviceJarFilepath()));
+            pw.println(String.format("exec app_process /system/bin %s \"$@\"",
+                    JAR_MAIN_CLASS_NAME));
+        } finally {
+            if (pw != null) {
+                pw.close();
+            }
+        }
+
+        return tempFile;
+    }
+
+    /**
+     * Helper class collecting all pids returned by 'adb jdwp' command.
+     */
+    private class AdbJdwpOutputReader implements Runnable {
+        /**
+         * A list of all pids with a JDWP connection returned by 'adb jdwp'.
+         */
+        private final List<String> lines = new ArrayList<String>();
+
+        /**
+         * The input stream of the process running 'adb jdwp'.
+         */
+        private InputStream in;
+
+        public List<String> listPidsWithAdbJdwp() throws Exception {
+            // The 'adb jdwp' command does not return normally, it only terminates with Ctrl^C.
+            // Therefore we cannot use ITestDevice.executeAdbCommand but need to run that command
+            // in the background. Since we know the tested app is already running, we only need to
+            // capture the output for a short amount of time before stopping the 'adb jdwp'
+            // command.
+            String[] adbJdwpCommand = buildAdbCommand("jdwp");
+            Process adbProcess = RunUtil.getDefault().runCmdInBackground(adbJdwpCommand);
+            in = adbProcess.getInputStream();
+
+            // Read the output for 5s in a separate thread before stopping the command.
+            Thread t = new Thread(this);
+            t.start();
+            Thread.sleep(5000);
+
+            // Kill the 'adb jdwp' process and wait for the thread to stop.
+            adbProcess.destroy();
+            t.join();
+
+            return lines;
+        }
+
+        @Override
+        public void run() {
+            BufferedReader br = null;
+            try {
+                br = new BufferedReader(new InputStreamReader(in));
+                String line;
+                while ((line = readLineIgnoreException(br)) != null) {
+                    lines.add(line);
+                }
+            } catch (IOException e) {
+                CLog.e(e);
+            } finally {
+                if (br != null) {
+                    try {
+                        br.close();
+                    } catch (IOException e) {
+                        // Ignore it.
+                    }
+                }
+            }
+        }
+
+        private String readLineIgnoreException(BufferedReader reader) throws IOException {
+            try {
+                return reader.readLine();
+            } catch (IOException e) {
+                if (e instanceof EOFException) {
+                    // This is expected when the process's input stream is closed.
+                    return null;
+                } else {
+                    throw e;
+                }
+            }
+        }
+    }
+
+    private String[] buildAdbCommand(String... args) {
+        return ArrayUtil.buildArray(new String[] {"adb", "-s", getDevice().getSerialNumber()},
+                args);
+    }
+
+    private boolean createRemoteDir(String remoteFilePath) throws DeviceNotAvailableException {
+        if (getDevice().doesFileExist(remoteFilePath)) {
+            return true;
+        }
+        File remoteFile = new File(remoteFilePath);
+        String parentPath = remoteFile.getParent();
+        if (parentPath != null) {
+            if (!createRemoteDir(parentPath)) {
+                return false;
+            }
+        }
+        getDevice().executeShellCommand(String.format("mkdir %s", remoteFilePath));
+        return getDevice().doesFileExist(remoteFilePath);
+    }
+}
diff --git a/hostsidetests/theme/assets/21/400dpi.zip b/hostsidetests/theme/assets/21/400dpi.zip
index 17efbbe..6d62e5b 100644
--- a/hostsidetests/theme/assets/21/400dpi.zip
+++ b/hostsidetests/theme/assets/21/400dpi.zip
Binary files differ
diff --git a/libs/commonutil/Android.mk b/libs/commonutil/Android.mk
new file mode 100644
index 0000000..9c131b0
--- /dev/null
+++ b/libs/commonutil/Android.mk
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include $(call all-subdir-makefiles)
+
+# ======================================================
+# Build a static host library for the AbiUtils
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := src/com/android/cts/util/AbiUtils.java
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE := ctsabiutilslib
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/libs/commonutil/src/com/android/cts/util/AbiUtils.java b/libs/commonutil/src/com/android/cts/util/AbiUtils.java
index 4a34c6f..42336f3 100644
--- a/libs/commonutil/src/com/android/cts/util/AbiUtils.java
+++ b/libs/commonutil/src/com/android/cts/util/AbiUtils.java
@@ -157,10 +157,44 @@
     }
 
     /**
+     * @return the test name portion of the test id.
+     *         e.g. armeabi-v7a android.mytest = android.mytest
+     */
+    public static String parseTestName(String id) {
+        return parseId(id)[1];
+    }
+
+    /**
+     * @return the abi portion of the test id.
+     *         e.g. armeabi-v7a android.mytest = armeabi-v7a
+     */
+    public static String parseAbi(String id) {
+        return parseId(id)[0];
+    }
+
+    /**
      * @param name The name of the ABI.
      * @return The bitness of the ABI with the given name
      */
     public static String getBitness(String name) {
         return ABIS_32BIT.contains(name) ? "32" : "64";
     }
+
+    /**
+     * @param abilistString A comma separated string containing abis.
+     * @return A List of Strings containing valid ABIs.
+     */
+    public static Set<String> parseAbiList(String unsupportedAbiDescription) {
+        Set<String> abiSet = new HashSet<>();
+        String[] descSegments = unsupportedAbiDescription.split(":");
+        if (descSegments.length == 2) {
+            for (String abi : descSegments[1].split(",")) {
+                String trimmedAbi = abi.trim();
+                if (isAbiSupportedByCts(trimmedAbi)) {
+                    abiSet.add(trimmedAbi);
+                }
+            }
+        }
+        return abiSet;
+    }
 }
diff --git a/suite/cts/deviceTests/browserbench/src/com/android/cts/browser/BrowserBenchTest.java b/suite/cts/deviceTests/browserbench/src/com/android/cts/browser/BrowserBenchTest.java
index 997f730..d74ddb2 100644
--- a/suite/cts/deviceTests/browserbench/src/com/android/cts/browser/BrowserBenchTest.java
+++ b/suite/cts/deviceTests/browserbench/src/com/android/cts/browser/BrowserBenchTest.java
@@ -17,6 +17,7 @@
 package com.android.cts.browser;
 
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.cts.util.WatchDog;
 import android.net.Uri;
 import android.provider.Browser;
@@ -70,10 +71,12 @@
     private volatile int mRunIndex;
     /** stores results for each runs. last entry will be the final score. */
     private LinkedHashMap<String, double[]> mResultsMap;
+    private PackageManager mPackageManager;
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+        mPackageManager = getInstrumentation().getContext().getPackageManager();
         mWebServer = new CtsTestServer(getContext()) {
             @Override
             protected HttpResponse onPost(HttpRequest request) throws Exception {
@@ -124,6 +127,10 @@
 
     @TimeoutReq(minutes = 60)
     public void testOctane() throws InterruptedException {
+        if (!isBrowserSupported()) {
+            Log.i(TAG, "Skipping test for device with no supported browser");
+            return;
+        }
         String url = mWebServer.getAssetUrl(OCTANE_START_FILE) + "?auto=1";
         final int kRepeat = 5;
         doTest(url, ResultType.LOWER_BETTER, ResultUnit.MS,
@@ -167,4 +174,13 @@
             numberToProcess++;
         }
     }
+
+    /**
+     * @return true iff this device is has a working browser.
+     */
+    private boolean isBrowserSupported() {
+        return !(mPackageManager.hasSystemFeature("android.hardware.type.television")
+                 || mPackageManager.hasSystemFeature("android.software.leanback")
+                 || mPackageManager.hasSystemFeature("android.hardware.type.watch"));
+    }
 }
diff --git a/tests/JobScheduler/Android.mk b/tests/JobScheduler/Android.mk
new file mode 100755
index 0000000..499abde
--- /dev/null
+++ b/tests/JobScheduler/Android.mk
@@ -0,0 +1,34 @@
+# 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)
+
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := optional
+
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+# Must match the package name in CtsTestCaseList.mk
+LOCAL_PACKAGE_NAME := CtsJobSchedulerDeviceTestCases
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/JobScheduler/AndroidManifest.xml b/tests/JobScheduler/AndroidManifest.xml
new file mode 100755
index 0000000..17cf399
--- /dev/null
+++ b/tests/JobScheduler/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.jobscheduler.cts.deviceside">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+
+        <service android:name="android.jobscheduler.MockJobService"
+            android:permission="android.permission.BIND_JOB_SERVICE" />
+    </application>
+
+    <!--  self-instrumenting test package. -->
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:label="JobScheduler device-side tests"
+        android:targetPackage="android.jobscheduler.cts.deviceside" >
+        <meta-data
+            android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+</manifest>
+
diff --git a/tests/JobScheduler/src/android/jobscheduler/MockJobService.java b/tests/JobScheduler/src/android/jobscheduler/MockJobService.java
new file mode 100644
index 0000000..a0177e2
--- /dev/null
+++ b/tests/JobScheduler/src/android/jobscheduler/MockJobService.java
@@ -0,0 +1,118 @@
+/*
+ * 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.jobscheduler;
+
+import android.annotation.TargetApi;
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Handles callback from the framework {@link android.app.job.JobScheduler}. The behaviour of this
+ * class is configured through the static
+ * {@link TestEnvironment}.
+ */
+@TargetApi(21)
+public class MockJobService extends JobService {
+    private static final String TAG = "MockJobService";
+
+    /** Wait this long before timing out the test. */
+    private static final long DEFAULT_TIMEOUT_MILLIS = 5000L; // 5 seconds.
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        Log.e(TAG, "Created test service.");
+    }
+
+    @Override
+    public boolean onStartJob(JobParameters params) {
+        Log.i(TAG, "Test job executing: " + params.getJobId());
+
+        TestEnvironment.getTestEnvironment().notifyExecution(params.getJobId());
+        return false;  // No work to do.
+    }
+
+    @Override
+    public boolean onStopJob(JobParameters params) {
+        return false;
+    }
+
+    /**
+     * Configures the expected behaviour for each test. This object is shared across consecutive
+     * tests, so to clear state each test is responsible for calling
+     * {@link TestEnvironment#setUp()}.
+     */
+    public static final class TestEnvironment {
+
+        private static TestEnvironment kTestEnvironment;
+        public static final int INVALID_JOB_ID = -1;
+
+        private CountDownLatch mLatch;
+        private int mExecutedJobId;
+
+        public static TestEnvironment getTestEnvironment() {
+            if (kTestEnvironment == null) {
+                kTestEnvironment = new TestEnvironment();
+            }
+            return kTestEnvironment;
+        }
+
+        /**
+         * Block the test thread, waiting on the JobScheduler to execute some previously scheduled
+         * job on this service.
+         */
+        public boolean awaitExecution() throws InterruptedException {
+            final boolean executed = mLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+            return executed;
+        }
+
+        /**
+         * Block the test thread, expecting to timeout but still listening to ensure that no jobs
+         * land in the interim.
+         * @return True if the latch timed out waiting on an execution.
+         */
+        public boolean awaitTimeout() throws InterruptedException {
+            return !mLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+        }
+
+        private void notifyExecution(int jobId) {
+            Log.d(TAG, "Job executed:" + jobId);
+            mExecutedJobId = jobId;
+            mLatch.countDown();
+        }
+
+        public void setExpectedExecutions(int numExecutions) {
+            // For no executions expected, set count to 1 so we can still block for the timeout.
+            if (numExecutions == 0) {
+                mLatch = new CountDownLatch(1);
+            } else {
+                mLatch = new CountDownLatch(numExecutions);
+            }
+        }
+
+        /** Called in each testCase#setup */
+        public void setUp() {
+            mLatch = null;
+            mExecutedJobId = INVALID_JOB_ID;
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
new file mode 100644
index 0000000..a83f7a9
--- /dev/null
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
@@ -0,0 +1,287 @@
+/*
+ * 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.jobscheduler.cts;
+
+
+import android.annotation.TargetApi;
+import android.app.job.JobInfo;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiManager;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Schedules jobs with the {@link android.app.job.JobScheduler} that have network connectivity
+ * constraints.
+ * Requires manipulating the {@link android.net.wifi.WifiManager} to ensure an unmetered network.
+ * Similarly, requires that the phone be connected to a wifi hotspot, or else the test will fail.
+ */
+@TargetApi(21)
+public class ConnectivityConstraintTest extends ConstraintTest {
+    private static final String TAG = "ConnectivityConstraintTest";
+
+    /** Unique identifier for the job scheduled by this suite of tests. */
+    public static final int CONNECTIVITY_JOB_ID = ConnectivityConstraintTest.class.hashCode();
+
+    private WifiManager mWifiManager;
+    private ConnectivityManager mCm;
+
+    /** Whether the device running these tests supports WiFi. */
+    private boolean mHasWifi;
+    /** Whether the device running these tests supports telephony. */
+    private boolean mHasTelephony;
+
+    private JobInfo.Builder mBuilder;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
+        mCm =
+                (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+
+        PackageManager packageManager = mContext.getPackageManager();
+        mHasWifi = packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI);
+        mHasTelephony = packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+        mBuilder =
+                new JobInfo.Builder(CONNECTIVITY_JOB_ID, kJobServiceComponent);
+    }
+
+    // --------------------------------------------------------------------------------------------
+    // Positives - schedule jobs under conditions that require them to pass.
+    // --------------------------------------------------------------------------------------------
+
+    /**
+     * Schedule a job that requires a WiFi connection, and assert that it executes when the device
+     * is connected to WiFi. This will fail if a wifi connection is unavailable.
+     */
+    public void testUnmeteredConstraintExecutes_withWifi() throws Exception {
+        if (!mHasWifi) {
+            Log.d(TAG, "Skipping test that requires the device be WiFi enabled.");
+            return;
+        }
+        connectToWiFi();
+
+        kTestEnvironment.setExpectedExecutions(1);
+        mJobScheduler.schedule(
+                mBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
+                        .build());
+
+        sendExpediteStableChargingBroadcast();
+
+        assertTrue("Job with unmetered constraint did not fire on WiFi.",
+                kTestEnvironment.awaitExecution());
+    }
+
+    /**
+     * Schedule a job with a connectivity constraint, and ensure that it executes on WiFi.
+     */
+    public void testConnectivityConstraintExecutes_withWifi() throws Exception {
+        if (!mHasWifi) {
+            Log.d(TAG, "Skipping test that requires the device be WiFi enabled.");
+            return;
+        }
+        connectToWiFi();
+
+        kTestEnvironment.setExpectedExecutions(1);
+        mJobScheduler.schedule(
+                mBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+                        .build());
+
+        sendExpediteStableChargingBroadcast();
+
+        assertTrue("Job with connectivity constraint did not fire on WiFi.",
+                kTestEnvironment.awaitExecution());
+    }
+
+    /**
+     * Schedule a job with a connectivity constraint, and ensure that it executes on on a mobile
+     * data connection.
+     */
+    public void testConnectivityConstraintExecutes_withMobile() throws Exception {
+        if (!checkDeviceSupportsMobileData()) {
+            return;
+        }
+        disconnectWifiToConnectToMobile();
+
+        kTestEnvironment.setExpectedExecutions(1);
+        mJobScheduler.schedule(
+                mBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
+                        .build());
+
+        sendExpediteStableChargingBroadcast();
+
+        assertTrue("Job with connectivity constraint did not fire on mobile.",
+                kTestEnvironment.awaitExecution());
+    }
+
+    // --------------------------------------------------------------------------------------------
+    // Negatives - schedule jobs under conditions that require that they fail.
+    // --------------------------------------------------------------------------------------------
+
+    /**
+     * Schedule a job that requires a WiFi connection, and assert that it fails when the device is
+     * connected to a cellular provider.
+     * This test assumes that if the device supports a mobile data connection, then this connection
+     * will be available.
+     */
+    public void testUnmeteredConstraintFails_withMobile() throws Exception {
+        if (!checkDeviceSupportsMobileData()) {
+            return;
+        }
+        disconnectWifiToConnectToMobile();
+
+        kTestEnvironment.setExpectedExecutions(0);
+        mJobScheduler.schedule(
+                mBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
+                        .build());
+        sendExpediteStableChargingBroadcast();
+
+        assertTrue("Job requiring unmetered connectivity still executed on mobile.",
+                kTestEnvironment.awaitTimeout());
+    }
+
+    /**
+     * Determine whether the device running these CTS tests should be subject to tests involving
+     * mobile data.
+     * @return True if this device will support a mobile data connection.
+     */
+    private boolean checkDeviceSupportsMobileData() {
+        if (!mHasTelephony) {
+            Log.d(TAG, "Skipping test that requires telephony features, not supported by this" +
+                    " device");
+            return false;
+        }
+        if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
+            Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Ensure WiFi is enabled, and block until we've verified that we are in fact connected.
+     * Taken from {@link android.net.http.cts.ApacheHttpClientTest}.
+     */
+    private void connectToWiFi() throws InterruptedException {
+        if (!mWifiManager.isWifiEnabled()) {
+            ConnectivityActionReceiver receiver =
+                    new ConnectivityActionReceiver(ConnectivityManager.TYPE_WIFI,
+                            NetworkInfo.State.CONNECTED);
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+            mContext.registerReceiver(receiver, filter);
+
+            assertTrue(mWifiManager.setWifiEnabled(true));
+            assertTrue("Wifi must be configured to connect to an access point for this test.",
+                    receiver.waitForStateChange());
+
+            mContext.unregisterReceiver(receiver);
+        }
+    }
+
+    private void disconnectWifiToConnectToMobile() throws InterruptedException {
+        if (mHasWifi && mWifiManager.isWifiEnabled()) {
+            ConnectivityActionReceiver connectMobileReceiver =
+                    new ConnectivityActionReceiver(ConnectivityManager.TYPE_MOBILE,
+                            NetworkInfo.State.CONNECTED);
+            ConnectivityActionReceiver disconnectWifiReceiver =
+                    new ConnectivityActionReceiver(ConnectivityManager.TYPE_WIFI,
+                            NetworkInfo.State.DISCONNECTED);
+            IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
+            mContext.registerReceiver(connectMobileReceiver, filter);
+            mContext.registerReceiver(disconnectWifiReceiver, filter);
+
+            assertTrue(mWifiManager.setWifiEnabled(false));
+            assertTrue("Failure disconnecting from WiFi.",
+                    disconnectWifiReceiver.waitForStateChange());
+            assertTrue("Device must have access to a metered network for this test.",
+                    connectMobileReceiver.waitForStateChange());
+
+            mContext.unregisterReceiver(connectMobileReceiver);
+            mContext.unregisterReceiver(disconnectWifiReceiver);
+        }
+    }
+
+    /** Capture the last connectivity change's network type and state. */
+    private class ConnectivityActionReceiver extends BroadcastReceiver {
+
+        private final CountDownLatch mReceiveLatch = new CountDownLatch(1);
+
+        private final int mNetworkType;
+
+        private final NetworkInfo.State mExpectedState;
+
+        ConnectivityActionReceiver(int networkType, NetworkInfo.State expectedState) {
+            mNetworkType = networkType;
+            mExpectedState = expectedState;
+        }
+
+        public void onReceive(Context context, Intent intent) {
+            // Dealing with a connectivity changed event for this network type.
+            final int networkTypeChanged =
+                    intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, -1);
+            if (networkTypeChanged == -1) {
+                Log.e(TAG, "No network type provided in intent");
+                return;
+            }
+
+            if (networkTypeChanged != mNetworkType) {
+                // Only track changes for the connectivity event that we are interested in.
+                return;
+            }
+            // Pull out the NetworkState object that we're interested in. Necessary because
+            // the ConnectivityManager will filter on uid for background connectivity.
+            NetworkInfo[] allNetworkInfo = mCm.getAllNetworkInfo();
+            NetworkInfo networkInfo = null;
+            for (int i=0; i<allNetworkInfo.length; i++) {
+                NetworkInfo ni = allNetworkInfo[i];
+                if (ni.getType() == mNetworkType) {
+                    networkInfo =  ni;
+                    break;
+                }
+            }
+            if (networkInfo == null) {
+                Log.e(TAG, "Could not find correct network type.");
+                return;
+            }
+
+            NetworkInfo.State networkState = networkInfo.getState();
+            Log.i(TAG, "Network type: " + mNetworkType + " State: " + networkState);
+            if (networkState == mExpectedState) {
+                mReceiveLatch.countDown();
+            }
+        }
+
+        public boolean waitForStateChange() throws InterruptedException {
+            return mReceiveLatch.await(30, TimeUnit.SECONDS) || hasExpectedState();
+        }
+
+        private boolean hasExpectedState() {
+            return mExpectedState == mCm.getNetworkInfo(mNetworkType).getState();
+        }
+    }
+
+}
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/ConstraintTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/ConstraintTest.java
new file mode 100644
index 0000000..b9a498f
--- /dev/null
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/ConstraintTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.jobscheduler.cts;
+
+import android.annotation.TargetApi;
+import android.app.job.JobScheduler;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.jobscheduler.MockJobService;
+import android.test.AndroidTestCase;
+
+/**
+ * Common functionality from which the other test case classes derive.
+ */
+@TargetApi(21)
+public abstract class ConstraintTest extends AndroidTestCase {
+    /** Force the scheduler to consider the device to be on stable charging. */
+    private static final Intent EXPEDITE_STABLE_CHARGING =
+            new Intent("com.android.server.task.controllers.BatteryController.ACTION_CHARGING_STABLE");
+
+    /** Environment that notifies of JobScheduler callbacks. */
+    static MockJobService.TestEnvironment kTestEnvironment =
+            MockJobService.TestEnvironment.getTestEnvironment();
+    /** Handle for the service which receives the execution callbacks from the JobScheduler. */
+    static ComponentName kJobServiceComponent;
+    JobScheduler mJobScheduler;
+
+    @Override
+    public void setUp() throws Exception {
+        kTestEnvironment.setUp();
+        kJobServiceComponent = new ComponentName(getContext(), MockJobService.class);
+        mJobScheduler = (JobScheduler) getContext().getSystemService(Context.JOB_SCHEDULER_SERVICE);
+        mJobScheduler.cancelAll();
+    }
+
+    /**
+     * The scheduler will usually only flush its queue of unexpired jobs when the device is
+     * considered to be on stable power - that is, plugged in for a period of 2 minutes.
+     * Rather than wait for this to happen, we cheat and send this broadcast instead.
+     */
+    protected void sendExpediteStableChargingBroadcast() {
+        getContext().sendBroadcast(EXPEDITE_STABLE_CHARGING);
+    }
+}
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/TimingConstraintsTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/TimingConstraintsTest.java
new file mode 100644
index 0000000..36f44ef
--- /dev/null
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/TimingConstraintsTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.jobscheduler.cts;
+
+import android.annotation.TargetApi;
+import android.app.job.JobInfo;
+
+/**
+ * Schedules jobs with various timing constraints and ensures that they are executed when
+ * appropriate.
+ */
+@TargetApi(21)
+public class TimingConstraintsTest extends ConstraintTest {
+    private static final int TIMING_JOB_ID = TimingConstraintsTest.class.hashCode() + 0;
+    private static final int CANCEL_JOB_ID = TimingConstraintsTest.class.hashCode() + 1;
+
+    public void testScheduleOnce() throws Exception {
+        JobInfo oneTimeJob = new JobInfo.Builder(TIMING_JOB_ID, kJobServiceComponent)
+                        .setOverrideDeadline(1000)  // 1 secs
+                        .build();
+
+        kTestEnvironment.setExpectedExecutions(1);
+        mJobScheduler.schedule(oneTimeJob);
+        final boolean executed = kTestEnvironment.awaitExecution();
+        assertTrue("Timed out waiting for override deadline.", executed);
+    }
+
+    public void testSchedulePeriodic() throws Exception {
+        JobInfo periodicJob =
+                new JobInfo.Builder(TIMING_JOB_ID, kJobServiceComponent)
+                        .setPeriodic(1000L)  // 1 second period.
+                        .build();
+
+        kTestEnvironment.setExpectedExecutions(3);
+        mJobScheduler.schedule(periodicJob);
+        final boolean countedDown = kTestEnvironment.awaitExecution();
+        assertTrue("Timed out waiting for periodic jobs to execute", countedDown);
+    }
+
+    public void testCancel() throws Exception {
+        JobInfo cancelJob = new JobInfo.Builder(CANCEL_JOB_ID, kJobServiceComponent)
+                .setOverrideDeadline(2000L)
+                .build();
+
+        kTestEnvironment.setExpectedExecutions(0);
+        mJobScheduler.schedule(cancelJob);
+        // Now cancel it.
+        mJobScheduler.cancel(CANCEL_JOB_ID);
+        assertTrue("Cancel failed: job executed when it shouldn't have.",
+                kTestEnvironment.awaitTimeout());
+    }
+}
\ No newline at end of file
diff --git a/tests/app/src/android/app/cts/MockAlarmReceiver.java b/tests/app/src/android/app/cts/MockAlarmReceiver.java
index 5060cef..8745db6 100644
--- a/tests/app/src/android/app/cts/MockAlarmReceiver.java
+++ b/tests/app/src/android/app/cts/MockAlarmReceiver.java
@@ -25,17 +25,21 @@
  * this class  receive alarm from AlarmManagerTest
  */
 public class MockAlarmReceiver extends BroadcastReceiver {
-    public boolean alarmed = false;
-    private Object mSync = new Object();
-    public static final String MOCKACTION = "android.app.AlarmManagerTest.TEST_ALARMRECEIVER";
+    private final Object mSync = new Object();
+    public final String mTargetAction;
 
-    public long elapsedTime;
-    public long rtcTime;
+    public volatile boolean alarmed = false;
+    public volatile long elapsedTime;
+    public volatile long rtcTime;
+
+    public MockAlarmReceiver(String targetAction) {
+        mTargetAction = targetAction;
+    }
 
     @Override
     public void onReceive(Context context, Intent intent) {
         final String action = intent.getAction();
-        if (action.equals(MOCKACTION)) {
+        if (action.equals(mTargetAction)) {
             synchronized (mSync) {
                 alarmed = true;
                 elapsedTime = SystemClock.elapsedRealtime();
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index 8adf345..dd8660f 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -1,10 +1,25 @@
 [
 {
-  description: "signature test stil needs more work",
+  description: "the UsageStats is not yet stable enough",
   names: [
-    "android.signature.cts.SignatureTest#testSignature"
+    "android.app.usage.cts.UsageStatsTest"
   ],
-  bug: 17894722
+  bug: 17536113
+},
+{
+  description: "the ConnectivityConstraintTest are not yet stable",
+  names: [
+    "android.jobscheduler.cts.ConnectivityConstraintTest"
+  ],
+  bug: 18117279
+},
+{
+  description: "tests a fragile by nature as they rely on hardcoded behavior",
+  names: [
+    "android.accessibilityservice.cts.AccessibilityTextTraversalTest#testActionNextAndPreviousAtGranularityPageOverText",
+    "android.accessibilityservice.cts.AccessibilityTextTraversalTest#testActionNextAndPreviousAtGranularityPageOverTextExtend"
+  ],
+  bug: 17595050
 },
 {
   description: "Not all jdwp features are currently supported. These tests will fail",
@@ -58,14 +73,18 @@
   description: "permissions for the API previously used in the test has changed, making it impossible to pass",
   names: [
     "android.openglperf.cts.GlAppSwitchTest#testGlActivitySwitchingFast",
-    "android.openglperf.cts.GlAppSwitchTest#testGlActivitySwitchingSlow",
-    "android.openglperf.cts.GlVboPerfTest#testVboVsNonVboPerfGeometry0",
-    "android.openglperf.cts.GlVboPerfTest#testVboVsNonVboPerfGeometry1",
-    "android.openglperf.cts.GlVboPerfTest#testVboWithVaryingIndexBufferNumbers"
+    "android.openglperf.cts.GlAppSwitchTest#testGlActivitySwitchingSlow"
   ],
   bug: 17394321
 },
 {
+  description: "unexpected failures",
+  names: [
+    "android.openglperf.cts.GlVboPerfTest#testVboWithVaryingIndexBufferNumbers"
+  ],
+  bug: 18091590
+},
+{
   description: "these tests require a good test scene, so they fail if run in random conditions",
   names: [
     "android.hardware.camera2.cts.AllocationTest#testBlackWhite",
@@ -74,6 +93,13 @@
   bug: 17530117
 },
 {
+  description: "this test removes the stay-awake option, causing the screen to turn off during the execution of subsequent tests",
+  names: [
+    "android.admin.cts.DevicePolicyManagerTest#testMaximumTimeToLock"
+  ],
+  bug: 18002490
+},
+{
   description: "these tests locks the screen with an emtpy password or swipe-to-unlock, blocking subsequent test to dismiss keyguard",
   names: [
     "android.admin.cts.DevicePolicyManagerTest#testPasswordQuality_something",
@@ -322,5 +348,21 @@
     "android.media.cts.ImageReaderDecoderTest#testHwAVCDecode360pForFlexibleYuv"
   ],
   bug: 17144778
+},
+{
+  description: "Roboto font tests are not yet known good on all devices",
+  names: [
+    "android.uirendering.cts.testclasses.FontRenderingTests"
+  ],
+  bug: 17109280
+},
+{
+  description: "android.keystore tests will replace these tests",
+  names: [
+    "com.android.org.conscrypt.MacTest#test_getInstance_OpenSSL_ENGINE",
+    "com.android.org.conscrypt.NativeCryptoTest#test_ENGINE_by_id_TestEngine",
+    "com.android.org.conscrypt.SignatureTest#test_getInstance_OpenSSL_ENGINE"
+  ],
+  bug: 18030049
 }
 ]
diff --git a/tests/expectations/unsupportedabis.txt b/tests/expectations/unsupportedabis.txt
index 520d750..7ad3682 100644
--- a/tests/expectations/unsupportedabis.txt
+++ b/tests/expectations/unsupportedabis.txt
@@ -2,10 +2,14 @@
 {
   description: "Tests not supporting: arm64-v8a, x86_64, mips64",
   names: [
-    "android.sample.cts.SampleDeviceResultTest",
-    "android.sample.cts.SampleDeviceTest",
-    "android.sample.cts.SampleHostResultTest",
-    "android.sample.cts.SampleHostTest"
+    "android.bionic.malloc#pvalloc_overflow",
+    "android.bionic.malloc#pvalloc_std",
+    "android.bionic.malloc#valloc_overflow",
+    "android.bionic.malloc#valloc_std",
+    "android.renderscriptlegacy.cts.LeakTest",
+    "android.renderscriptlegacy.cts.RSBase",
+    "android.renderscriptlegacy.cts.RSBaseCompute",
+    "android.renderscriptlegacy.cts.VersionTest"
   ]
 }
 ]
diff --git a/tests/signature/src/android/signature/cts/JDiffClassDescription.java b/tests/signature/src/android/signature/cts/JDiffClassDescription.java
index 7ea9911..afcaa15 100644
--- a/tests/signature/src/android/signature/cts/JDiffClassDescription.java
+++ b/tests/signature/src/android/signature/cts/JDiffClassDescription.java
@@ -26,8 +26,10 @@
 import java.lang.reflect.TypeVariable;
 import java.lang.reflect.WildcardType;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -53,6 +55,8 @@
 
     @SuppressWarnings("unchecked")
     private Class<?> mClass;
+    // A map of field name to field of the fields contained in {@code mClass}
+    private Map<String, Field> mClassFieldMap;
 
     private String mPackageName;
     private String mShortClassName;
@@ -437,9 +441,12 @@
     public void checkSignatureCompliance() {
         checkClassCompliance();
         if (mClass != null) {
+            mClassFieldMap = buildFieldMap(mClass);
             checkFieldsCompliance();
             checkConstructorCompliance();
             checkMethodCompliance();
+        } else {
+            mClassFieldMap = null;
         }
     }
 
@@ -724,7 +731,7 @@
                     Type type = f.getGenericType();
                     if (type != null) {
                         genericTypeName = type instanceof Class ? ((Class) type).getName() :
-                            type.toString();
+                            type.toString().replace('$', '.');
                     }
                     if (genericTypeName == null || !genericTypeName.equals(field.mFieldType)) {
                         mResultObserver.notifyFailure(
@@ -751,14 +758,8 @@
      * @param field the field description to find
      * @return the reflected field, or null if not found.
      */
-    private Field findMatchingField(JDiffField field){
-        Field[] fields = mClass.getDeclaredFields();
-        for (Field f : fields) {
-            if (f.getName().equals(field.mName)) {
-                return f;
-            }
-        }
-        return null;
+    private Field findMatchingField(JDiffField field) {
+        return mClassFieldMap.get(field.mName);
     }
 
     /**
@@ -1191,6 +1192,31 @@
         return paramType.replace("<? extends java.lang.Object>", "<?>");
     }
 
+    /**
+     * Scan a class (an its entire inheritance chain) for fields.
+     *
+     * @return a {@link Map} of fieldName to {@link Field}
+     */
+    private static Map<String, Field> buildFieldMap(Class testClass) {
+        Map<String, Field> fieldMap = new HashMap<String, Field>();
+        // Scan the superclass
+        if (testClass.getSuperclass() != null) {
+            fieldMap.putAll(buildFieldMap(testClass.getSuperclass()));
+        }
+
+        // Scan the interfaces
+        for (Class interfaceClass : testClass.getInterfaces()) {
+            fieldMap.putAll(buildFieldMap(interfaceClass));
+        }
+
+        // Check the fields in the test class
+        for (Field field : testClass.getDeclaredFields()) {
+            fieldMap.put(field.getName(), field);
+        }
+
+        return fieldMap;
+    }
+
     private static void loge(String message, Exception exception) {
         System.err.println(String.format("%s: %s", message, exception));
     }
diff --git a/tests/signature/src/android/signature/cts/SignatureTest.java b/tests/signature/src/android/signature/cts/SignatureTest.java
index e3099a9..85b77f8 100644
--- a/tests/signature/src/android/signature/cts/SignatureTest.java
+++ b/tests/signature/src/android/signature/cts/SignatureTest.java
@@ -69,8 +69,6 @@
     private static final String ATTRIBUTE_TYPE = "type";
     private static final String ATTRIBUTE_RETURN = "return";
 
-    private static ArrayList<String> mDebugArray = new ArrayList<String>();
-
     private HashSet<String> mKeyTagSet;
     private TestResultObserver mResultObserver;
 
@@ -85,6 +83,8 @@
             mErrorString.append(type.toString().toLowerCase());
             mErrorString.append(":\t");
             mErrorString.append(name);
+            mErrorString.append("\tError: ");
+            mErrorString.append(errorMessage);
         }
     }
 
@@ -109,7 +109,7 @@
         logd(String.format("Class: %s", rClass.toString()));
         Field[] fs = rClass.getFields();
         for (Field f : fs) {
-            logd(String.format("Field: %s", fs.toString()));
+            logd(String.format("Field: %s", f.toString()));
             try {
                 start(r.getXml(f.getInt(rClass)));
             } catch (Exception e) {
@@ -142,11 +142,12 @@
      * Signature test entry point.
      */
     private void start(XmlPullParser parser) throws XmlPullParserException, IOException {
-        logd(String.format("Parser: %s", parser.getName()));
-        logd(String.format("Parser: %s", parser.getNamespace()));
-        logd(String.format("Parser: %s", parser.getLineNumber()));
-        logd(String.format("Parser: %s", parser.getColumnNumber()));
-        logd(String.format("Parser: %s", parser.getPositionDescription()));
+        logd(String.format("Name: %s", parser.getName()));
+        logd(String.format("Text: %s", parser.getText()));
+        logd(String.format("Namespace: %s", parser.getNamespace()));
+        logd(String.format("Line Number: %s", parser.getLineNumber()));
+        logd(String.format("Column Number: %s", parser.getColumnNumber()));
+        logd(String.format("Position Description: %s", parser.getPositionDescription()));
         JDiffClassDescription currentClass = null;
         String currentPackage = "";
         JDiffMethod currentMethod = null;
@@ -204,7 +205,16 @@
                 currentClass.addField(field);
             } else {
                 throw new RuntimeException(
-                        "unknow tag exception:" + tagname);
+                        "unknown tag exception:" + tagname);
+            }
+            if (currentPackage != null) {
+                logd(String.format("currentPackage: %s", currentPackage));
+            }
+            if (currentClass != null) {
+                logd(String.format("currentClass: %s", currentClass.toSignatureString()));
+            }
+            if (currentMethod != null) {
+                logd(String.format("currentMethod: %s", currentMethod.toSignatureString()));
             }
         }
     }
diff --git a/tests/tests/usage/Android.mk b/tests/tests/app.usage/Android.mk
similarity index 100%
rename from tests/tests/usage/Android.mk
rename to tests/tests/app.usage/Android.mk
diff --git a/tests/tests/usage/AndroidManifest.xml b/tests/tests/app.usage/AndroidManifest.xml
similarity index 100%
rename from tests/tests/usage/AndroidManifest.xml
rename to tests/tests/app.usage/AndroidManifest.xml
diff --git a/tests/tests/usage/src/android/app/usage/cts/Activities.java b/tests/tests/app.usage/src/android/app/usage/cts/Activities.java
similarity index 100%
rename from tests/tests/usage/src/android/app/usage/cts/Activities.java
rename to tests/tests/app.usage/src/android/app/usage/cts/Activities.java
diff --git a/tests/tests/usage/src/android/app/usage/cts/UsageStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
similarity index 100%
rename from tests/tests/usage/src/android/app/usage/cts/UsageStatsTest.java
rename to tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
diff --git a/tests/tests/app/src/android/app/cts/AlarmManagerTest.java b/tests/tests/app/src/android/app/cts/AlarmManagerTest.java
index 0780101..bfc3e1d 100644
--- a/tests/tests/app/src/android/app/cts/AlarmManagerTest.java
+++ b/tests/tests/app/src/android/app/cts/AlarmManagerTest.java
@@ -25,45 +25,86 @@
 import android.cts.util.PollingCheck;
 import android.os.SystemClock;
 import android.test.AndroidTestCase;
+import android.util.Log;
 
 public class AlarmManagerTest extends AndroidTestCase {
-    private AlarmManager mAlarmManager;
+    public static final String MOCKACTION = "android.app.AlarmManagerTest.TEST_ALARMRECEIVER";
+    public static final String MOCKACTION2 = "android.app.AlarmManagerTest.TEST_ALARMRECEIVER2";
+
+    private AlarmManager mAm;
     private Intent mIntent;
     private PendingIntent mSender;
-    private Intent mServiceIntent;
+    private Intent mIntent2;
+    private PendingIntent mSender2;
 
     /*
      *  The default snooze delay: 5 seconds
      */
-    private final long SNOOZE_DELAY = 5 * 1000L;
+    private static final long SNOOZE_DELAY = 5 * 1000L;
     private long mWakeupTime;
     private MockAlarmReceiver mMockAlarmReceiver;
+    private MockAlarmReceiver mMockAlarmReceiver2;
 
-    private final int TIME_DELTA = 1000;
-    private final int TIME_DELAY = 5000;
+    private static final int TIME_DELTA = 1000;
+    private static final int TIME_DELAY = 10000;
 
-    class Sync {
-        public boolean mIsConnected;
-        public boolean mIsDisConnected;
-    }
+    // Receiver registration/unregistration between tests races with the system process, so
+    // we add a little buffer time here to allow the system to process before we proceed.
+    // This value is in milliseconds.
+    private static final long REGISTER_PAUSE = 250;
+
+    // Constants used for validating exact vs inexact alarm batching immunity.  We run a few
+    // trials of an exact alarm that is placed within an inexact alarm's window of opportunity,
+    // and mandate that the average observed delivery skew between the two be statistically
+    // significant -- i.e. that the two alarms are not being coalesced.  We also place an
+    // additional exact alarm only a short time after the inexact alarm's nominal trigger time.
+    // If exact alarms are allowed to batch with inexact ones this will tend to have no effect,
+    // but in the correct behavior -- inexact alarms not permitted to batch with exact ones --
+    // this additional exact alarm will have the effect of guaranteeing that the inexact alarm
+    // must fire no later than it -- i.e. a considerable time before the significant, later
+    // exact alarm.
+    //
+    // The test essentially amounts to requiring that the inexact MOCKACTION alarm and
+    // the much later exact MOCKACTION2 alarm fire far apart, always; with an implicit
+    // insistence that alarm batches are delivered at the head of their window.
+    private static final long TEST_WINDOW_LENGTH = 5 * 1000L;
+    private static final long TEST_ALARM_FUTURITY = 6 * 1000L;
+    private static final long FAIL_DELTA = 50;
+    private static final long NUM_TRIALS = 5;
+    private static final long MAX_NEAR_DELIVERIES = 2;
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
-        mIntent = new Intent(MockAlarmReceiver.MOCKACTION);
+
+        mAm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+
+        mIntent = new Intent(MOCKACTION)
+                .addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY);
         mSender = PendingIntent.getBroadcast(mContext, 0, mIntent, 0);
-        mMockAlarmReceiver = new MockAlarmReceiver();
-        IntentFilter filter = new IntentFilter(MockAlarmReceiver.MOCKACTION);
+        mMockAlarmReceiver = new MockAlarmReceiver(mIntent.getAction());
+
+        mIntent2 = new Intent(MOCKACTION2)
+                .addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+        mSender2 = PendingIntent.getBroadcast(mContext, 0, mIntent2, 0);
+        mMockAlarmReceiver2 = new MockAlarmReceiver(mIntent2.getAction());
+
+        IntentFilter filter = new IntentFilter(mIntent.getAction());
         mContext.registerReceiver(mMockAlarmReceiver, filter);
+
+        IntentFilter filter2 = new IntentFilter(mIntent2.getAction());
+        mContext.registerReceiver(mMockAlarmReceiver2, filter2);
+
+        Thread.sleep(REGISTER_PAUSE);
     }
 
     @Override
     protected void tearDown() throws Exception {
         super.tearDown();
-        if (mServiceIntent != null) {
-            mContext.stopService(mServiceIntent);
-        }
+        mContext.unregisterReceiver(mMockAlarmReceiver);
+        mContext.unregisterReceiver(mMockAlarmReceiver2);
+
+        Thread.sleep(REGISTER_PAUSE);
     }
 
     public void testSetTypes() throws Exception {
@@ -73,7 +114,7 @@
         // test parameter type is RTC_WAKEUP
         mMockAlarmReceiver.setAlarmedFalse();
         mWakeupTime = System.currentTimeMillis() + SNOOZE_DELAY;
-        mAlarmManager.set(AlarmManager.RTC_WAKEUP, mWakeupTime, mSender);
+        mAm.setExact(AlarmManager.RTC_WAKEUP, mWakeupTime, mSender);
         new PollingCheck(SNOOZE_DELAY + TIME_DELAY) {
             @Override
             protected boolean check() {
@@ -85,7 +126,7 @@
         // test parameter type is RTC
         mMockAlarmReceiver.setAlarmedFalse();
         mWakeupTime = System.currentTimeMillis() + SNOOZE_DELAY;
-        mAlarmManager.set(AlarmManager.RTC, mWakeupTime, mSender);
+        mAm.setExact(AlarmManager.RTC, mWakeupTime, mSender);
         new PollingCheck(SNOOZE_DELAY + TIME_DELAY) {
             @Override
             protected boolean check() {
@@ -97,7 +138,7 @@
         // test parameter type is ELAPSED_REALTIME
         mMockAlarmReceiver.setAlarmedFalse();
         mWakeupTime = SystemClock.elapsedRealtime() + SNOOZE_DELAY;
-        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, mWakeupTime, mSender);
+        mAm.setExact(AlarmManager.ELAPSED_REALTIME, mWakeupTime, mSender);
         new PollingCheck(SNOOZE_DELAY + TIME_DELAY) {
             @Override
             protected boolean check() {
@@ -109,7 +150,7 @@
         // test parameter type is ELAPSED_REALTIME_WAKEUP
         mMockAlarmReceiver.setAlarmedFalse();
         mWakeupTime = SystemClock.elapsedRealtime() + SNOOZE_DELAY;
-        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, mWakeupTime, mSender);
+        mAm.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, mWakeupTime, mSender);
         new PollingCheck(SNOOZE_DELAY + TIME_DELAY) {
             @Override
             protected boolean check() {
@@ -125,7 +166,7 @@
         // that would instead cause such alarms to never be triggered.
         mMockAlarmReceiver.setAlarmedFalse();
         mWakeupTime = -1000;
-        mAlarmManager.set(AlarmManager.RTC, mWakeupTime, mSender);
+        mAm.set(AlarmManager.RTC, mWakeupTime, mSender);
         new PollingCheck(TIME_DELAY) {
             @Override
             protected boolean check() {
@@ -134,10 +175,54 @@
         }.run();
     }
 
+    public void testExactAlarmBatching() throws Exception {
+        int deliveriesTogether = 0;
+        for (int i = 0; i < NUM_TRIALS; i++) {
+            final long now = System.currentTimeMillis();
+            final long windowStart = now + TEST_ALARM_FUTURITY;
+            final long exactStart = windowStart + TEST_WINDOW_LENGTH - 1;
+
+            mMockAlarmReceiver.setAlarmedFalse();
+            mMockAlarmReceiver2.setAlarmedFalse();
+            mAm.setWindow(AlarmManager.RTC_WAKEUP, windowStart, TEST_WINDOW_LENGTH, mSender);
+            mAm.setExact(AlarmManager.RTC_WAKEUP, exactStart, mSender2);
+
+            // Wait until a half-second beyond its target window, just to provide a
+            // little safety slop.
+            new PollingCheck(TEST_WINDOW_LENGTH + (windowStart - now) + 500) {
+                @Override
+                protected boolean check() {
+                    return mMockAlarmReceiver.alarmed;
+                }
+            }.run();
+
+            // Now wait until 1 sec beyond the expected exact alarm fire time, or for at
+            // least one second if we're already past the nominal exact alarm fire time
+            long timeToExact = Math.max(exactStart - System.currentTimeMillis() + 1000, 1000);
+            new PollingCheck(timeToExact) {
+                @Override
+                protected boolean check() {
+                    return mMockAlarmReceiver2.alarmed;
+                }
+            }.run();
+
+            // Success when we observe that the exact and windowed alarm are not being often
+            // delivered close together -- that is, when we can be confident that they are not
+            // being coalesced.
+            final long delta = Math.abs(mMockAlarmReceiver2.rtcTime - mMockAlarmReceiver.rtcTime);
+            Log.i("TEST", "[" + i + "]  delta = " + delta);
+            if (delta < FAIL_DELTA) {
+                deliveriesTogether++;
+                assertTrue("Exact alarms appear to be coalescing with inexact alarms",
+                        deliveriesTogether <= MAX_NEAR_DELIVERIES);
+            }
+        }
+    }
+
     public void testSetRepeating() throws Exception {
         mMockAlarmReceiver.setAlarmedFalse();
         mWakeupTime = System.currentTimeMillis() + SNOOZE_DELAY;
-        mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, mWakeupTime, TIME_DELAY / 2, mSender);
+        mAm.setRepeating(AlarmManager.RTC_WAKEUP, mWakeupTime, TIME_DELAY / 2, mSender);
         new PollingCheck(SNOOZE_DELAY + TIME_DELAY) {
             @Override
             protected boolean check() {
@@ -151,13 +236,13 @@
                 return mMockAlarmReceiver.alarmed;
             }
         }.run();
-        mAlarmManager.cancel(mSender);
+        mAm.cancel(mSender);
     }
 
     public void testCancel() throws Exception {
         mMockAlarmReceiver.setAlarmedFalse();
         mWakeupTime = System.currentTimeMillis() + SNOOZE_DELAY;
-        mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, mWakeupTime, 1000, mSender);
+        mAm.setRepeating(AlarmManager.RTC_WAKEUP, mWakeupTime, 1000, mSender);
         new PollingCheck(SNOOZE_DELAY + TIME_DELAY) {
             @Override
             protected boolean check() {
@@ -171,7 +256,7 @@
                 return mMockAlarmReceiver.alarmed;
             }
         }.run();
-        mAlarmManager.cancel(mSender);
+        mAm.cancel(mSender);
         Thread.sleep(TIME_DELAY);
         mMockAlarmReceiver.setAlarmedFalse();
         Thread.sleep(TIME_DELAY * 5);
@@ -179,8 +264,7 @@
     }
 
     public void testSetInexactRepeating() throws Exception {
-
-        mAlarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
+        mAm.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
                 AlarmManager.INTERVAL_FIFTEEN_MINUTES, mSender);
         SystemClock.setCurrentTimeMillis(System.currentTimeMillis()
                 + AlarmManager.INTERVAL_FIFTEEN_MINUTES);
diff --git a/tests/tests/bionic/Android.mk b/tests/tests/bionic/Android.mk
index 1a048c6..e1afd50 100644
--- a/tests/tests/bionic/Android.mk
+++ b/tests/tests/bionic/Android.mk
@@ -8,6 +8,9 @@
 LOCAL_MODULE := $(test_executable)
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 LOCAL_ADDITION_DEPENDENCIES := \
     $(LOCAL_PATH)/Android.mk \
@@ -31,6 +34,10 @@
 
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := $(list_executable)
+LOCAL_MULTILIB := both
+# Use the 32 bit list executable since it will include some 32 bit only tests.
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 LOCAL_ADDITION_DEPENDENCIES := \
     $(LOCAL_PATH)/Android.mk \
diff --git a/tests/tests/deqp/Android.mk b/tests/tests/deqp/Android.mk
new file mode 100644
index 0000000..d8a4dda
--- /dev/null
+++ b/tests/tests/deqp/Android.mk
@@ -0,0 +1,26 @@
+# 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.
+
+# Dummy target to make dEQP test list generation consistent with other tests.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# All APIs share the same package
+LOCAL_PACKAGE_NAME := com.drawelements.deqp
+
+include $(LOCAL_PATH)/deqp_gles2.mk
+include $(LOCAL_PATH)/deqp_gles3.mk
+include $(LOCAL_PATH)/deqp_gles31.mk
diff --git a/tests/tests/deqp/deqp_gles2.mk b/tests/tests/deqp/deqp_gles2.mk
new file mode 100644
index 0000000..3cd60da
--- /dev/null
+++ b/tests/tests/deqp/deqp_gles2.mk
@@ -0,0 +1,21 @@
+# 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.
+
+# Dummy target to make dEQP GLES2 test list generation consistent with other
+# tests.
+
+DEQP_API := gles2
+DEQP_TEST_NAME := dEQP-GLES2
+
+include $(BUILD_CTS_DEQP_PACKAGE)
diff --git a/tests/tests/deqp/deqp_gles3.mk b/tests/tests/deqp/deqp_gles3.mk
new file mode 100644
index 0000000..07dfdae
--- /dev/null
+++ b/tests/tests/deqp/deqp_gles3.mk
@@ -0,0 +1,21 @@
+# 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.
+
+# Dummy target to make dEQP GLES3 test list generation consistent with other
+# tests.
+
+DEQP_API := gles3
+DEQP_TEST_NAME := dEQP-GLES3
+
+include $(BUILD_CTS_DEQP_PACKAGE)
diff --git a/tests/tests/deqp/deqp_gles31.mk b/tests/tests/deqp/deqp_gles31.mk
new file mode 100644
index 0000000..7e45413
--- /dev/null
+++ b/tests/tests/deqp/deqp_gles31.mk
@@ -0,0 +1,21 @@
+# 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.
+
+# Dummy target to make dEQP GLES31 test list generation consistent with other
+# tests.
+
+DEQP_API := gles31
+DEQP_TEST_NAME := dEQP-GLES31
+
+include $(BUILD_CTS_DEQP_PACKAGE)
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
index ea15c19..90cb18a 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
@@ -78,7 +78,6 @@
     private static final int MAX_VIDEO_SNAPSHOT_IMAGES = 5;
     private static final int BURST_VIDEO_SNAPSHOT_NUM = 3;
     private static final int SLOWMO_SLOW_FACTOR = 4;
-    private static final int MAX_NUM_FRAME_DROP_ALLOWED = 3;
     private List<Size> mSupportedVideoSizes;
     private Surface mRecordingSurface;
     private MediaRecorder mMediaRecorder;
@@ -548,6 +547,8 @@
      */
     private void videoSnapshotTestByCamera(boolean burstTest)
             throws Exception {
+        final int NUM_SINGLE_SHOT_TEST = 5;
+        final int FRAMEDROP_TOLERANCE = 8;
         for (int profileId : mCamcorderProfileList) {
             int cameraId = Integer.valueOf(mCamera.getId());
             if (!CamcorderProfile.hasProfile(cameraId, profileId) ||
@@ -603,70 +604,89 @@
                         + videoSz.toString() + ".mp4";
             }
 
-            prepareRecordingWithProfile(profile);
+            int numTestIterations = burstTest ? 1 : NUM_SINGLE_SHOT_TEST;
+            int totalDroppedFrames = 0;
 
-            // prepare video snapshot
-            SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
-            SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
-            CaptureRequest.Builder videoSnapshotRequestBuilder =
-                    mCamera.createCaptureRequest((mStaticInfo.isHardwareLevelLegacy()) ?
-                            CameraDevice.TEMPLATE_RECORD : CameraDevice.TEMPLATE_VIDEO_SNAPSHOT);
+            for (int numTested = 0; numTested < numTestIterations; numTested++) {
+                prepareRecordingWithProfile(profile);
 
-            // prepare preview surface by using video size.
-            updatePreviewSurfaceWithVideoSize(videoSz);
+                // prepare video snapshot
+                SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
+                SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
+                CaptureRequest.Builder videoSnapshotRequestBuilder =
+                        mCamera.createCaptureRequest((mStaticInfo.isHardwareLevelLegacy()) ?
+                                CameraDevice.TEMPLATE_RECORD :
+                                CameraDevice.TEMPLATE_VIDEO_SNAPSHOT);
 
-            prepareVideoSnapshot(videoSnapshotRequestBuilder, imageListener);
+                // prepare preview surface by using video size.
+                updatePreviewSurfaceWithVideoSize(videoSz);
 
-            // Start recording
-            startRecording(/* useMediaRecorder */true, resultListener);
-            long startTime = SystemClock.elapsedRealtime();
+                prepareVideoSnapshot(videoSnapshotRequestBuilder, imageListener);
+                CaptureRequest request = videoSnapshotRequestBuilder.build();
 
-            // Record certain duration.
-            SystemClock.sleep(RECORDING_DURATION_MS / 2);
+                // Start recording
+                startRecording(/* useMediaRecorder */true, resultListener);
+                long startTime = SystemClock.elapsedRealtime();
 
-            // take a video snapshot
-            CaptureRequest request = videoSnapshotRequestBuilder.build();
-            if (burstTest) {
-                List<CaptureRequest> requests =
-                        new ArrayList<CaptureRequest>(BURST_VIDEO_SNAPSHOT_NUM);
-                for (int i = 0; i < BURST_VIDEO_SNAPSHOT_NUM; i++) {
-                    requests.add(request);
+                // Record certain duration.
+                SystemClock.sleep(RECORDING_DURATION_MS / 2);
+
+                // take video snapshot
+                if (burstTest) {
+                    List<CaptureRequest> requests =
+                            new ArrayList<CaptureRequest>(BURST_VIDEO_SNAPSHOT_NUM);
+                    for (int i = 0; i < BURST_VIDEO_SNAPSHOT_NUM; i++) {
+                        requests.add(request);
+                    }
+                    mSession.captureBurst(requests, resultListener, mHandler);
+                } else {
+                    mSession.capture(request, resultListener, mHandler);
                 }
-                mSession.captureBurst(requests, resultListener, mHandler);
-            } else {
-                mSession.capture(request, resultListener, mHandler);
-            }
 
-            // make sure recording is still going after video snapshot
-            SystemClock.sleep(RECORDING_DURATION_MS / 2);
+                // make sure recording is still going after video snapshot
+                SystemClock.sleep(RECORDING_DURATION_MS / 2);
 
-            // Stop recording and preview
-            stopRecording(/* useMediaRecorder */true);
-            int duration = (int) (SystemClock.elapsedRealtime() - startTime);
+                // Stop recording and preview
+                stopRecording(/* useMediaRecorder */true);
+                int duration = (int) (SystemClock.elapsedRealtime() - startTime);
 
-            // Validation recorded video
-            validateRecording(videoSz, duration);
+                // Validation recorded video
+                validateRecording(videoSz, duration);
 
-            if (burstTest) {
-                for (int i = 0; i < BURST_VIDEO_SNAPSHOT_NUM; i++) {
+                if (burstTest) {
+                    for (int i = 0; i < BURST_VIDEO_SNAPSHOT_NUM; i++) {
+                        Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
+                        validateVideoSnapshotCapture(image, videoSnapshotSz);
+                        image.close();
+                    }
+                } else {
+                    // validate video snapshot image
                     Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
                     validateVideoSnapshotCapture(image, videoSnapshotSz);
+
+                    // validate if there is framedrop around video snapshot
+                    totalDroppedFrames +=  validateFrameDropAroundVideoSnapshot(
+                            resultListener, image.getTimestamp());
+
+                    //TODO: validate jittering. Should move to PTS
+                    //validateJittering(resultListener);
+
                     image.close();
                 }
-            } else {
-                // validate video snapshot image
-                Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
-                validateVideoSnapshotCapture(image, videoSnapshotSz);
-
-                // validate if there is framedrop around video snapshot
-                validateFrameDropAroundVideoSnapshot(resultListener, image.getTimestamp());
-
-                //TODO: validate jittering. Should move to PTS
-                //validateJittering(resultListener);
-
-                image.close();
             }
 
+            if (!burstTest) {
+                Log.w(TAG, String.format("Camera %d Video size %s: Number of dropped frames " +
+                        "detected in %d trials is %d frames.", cameraId, videoSz.toString(),
+                        numTestIterations, totalDroppedFrames));
+                mCollector.expectLessOrEqual(
+                        String.format(
+                                "Camera %d Video size %s: Number of dropped frames %d must not"
+                                + " be larger than %d",
+                                cameraId, videoSz.toString(), totalDroppedFrames,
+                                FRAMEDROP_TOLERANCE),
+                        FRAMEDROP_TOLERANCE, totalDroppedFrames);
+            }
             closeImageReader();
         }
     }
@@ -867,8 +887,9 @@
     /**
      * Validate if video snapshot causes frame drop.
      * Here frame drop is defined as frame duration >= 2 * expected frame duration.
+     * Return the estimated number of frames dropped during video snapshot
      */
-    private void validateFrameDropAroundVideoSnapshot(
+    private int validateFrameDropAroundVideoSnapshot(
             SimpleCaptureCallback resultListener, long imageTimeStamp) {
         int expectedDurationMs = 1000 / mVideoFrameRate;
         CaptureResult prevResult = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
@@ -883,19 +904,11 @@
                         resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
                 long nextTS = getValueNotNull(nextResult, CaptureResult.SENSOR_TIMESTAMP);
                 int durationMs = (int) (currentTS - prevTS) / 1000000;
+                int totalFramesDropped = 0;
 
                 // Snapshots in legacy mode pause the preview briefly.  Skip the duration
                 // requirements for legacy mode unless this is fixed.
                 if (!mStaticInfo.isHardwareLevelLegacy()) {
-                    mCollector.expectTrue(
-                            String.format(
-                                    "Video %dx%d Frame drop detected before video snapshot: " +
-                                            "duration %dms (expected %dms)",
-                                    mVideoSize.getWidth(), mVideoSize.getHeight(),
-                                    durationMs, expectedDurationMs
-                            ),
-                            durationMs <= (expectedDurationMs * MAX_NUM_FRAME_DROP_ALLOWED)
-                    );
                     // Log a warning is there is any frame drop detected.
                     if (durationMs >= expectedDurationMs * 2) {
                         Log.w(TAG, String.format(
@@ -907,15 +920,6 @@
                     }
 
                     durationMs = (int) (nextTS - currentTS) / 1000000;
-                    mCollector.expectTrue(
-                            String.format(
-                                    "Video %dx%d Frame drop detected after video snapshot: " +
-                                            "duration %dms (expected %dms)",
-                                    mVideoSize.getWidth(), mVideoSize.getHeight(),
-                                    durationMs, expectedDurationMs
-                            ),
-                            durationMs <= (expectedDurationMs * MAX_NUM_FRAME_DROP_ALLOWED)
-                    );
                     // Log a warning is there is any frame drop detected.
                     if (durationMs >= expectedDurationMs * 2) {
                         Log.w(TAG, String.format(
@@ -925,8 +929,18 @@
                                 durationMs, expectedDurationMs
                         ));
                     }
+
+                    int totalDurationMs = (int) (nextTS - prevTS) / 1000000;
+                    // Rounding and minus 2 for the expected 2 frames interval
+                    totalFramesDropped =
+                            (totalDurationMs + expectedDurationMs / 2) /expectedDurationMs - 2;
+                    if (totalFramesDropped < 0) {
+                        Log.w(TAG, "totalFrameDropped is " + totalFramesDropped +
+                                ". Video frame rate might be too fast.");
+                    }
+                    totalFramesDropped = Math.max(0, totalFramesDropped);
                 }
-                return;
+                return totalFramesDropped;
             }
             prevTS = currentTS;
         }
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/StaticMetadata.java b/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
index fb2001f..a5c7083 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
@@ -57,7 +57,7 @@
     private static final long SENSOR_INFO_EXPOSURE_TIME_RANGE_MIN_AT_MOST = 100000L; // 100us
     private static final long SENSOR_INFO_EXPOSURE_TIME_RANGE_MAX_AT_LEAST = 100000000; // 100ms
     private static final int SENSOR_INFO_SENSITIVITY_RANGE_MIN_AT_MOST = 100;
-    private static final int SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST = 1600;
+    private static final int SENSOR_INFO_SENSITIVITY_RANGE_MAX_AT_LEAST = 800;
     private static final int STATISTICS_INFO_MAX_FACE_COUNT_MIN_AT_LEAST = 4;
     private static final int TONEMAP_MAX_CURVE_POINTS_AT_LEAST = 64;
     private static final int CONTROL_AE_COMPENSATION_RANGE_DEFAULT_MIN = -2;
diff --git a/tests/tests/hardware/src/android/hardware/cts/CameraTest.java b/tests/tests/hardware/src/android/hardware/cts/CameraTest.java
index 3476895..019bd21 100644
--- a/tests/tests/hardware/src/android/hardware/cts/CameraTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/CameraTest.java
@@ -1859,6 +1859,7 @@
         initializeMessageLooper(cameraId);
 
         // Test if the parameters exists and minimum fps <= maximum fps.
+        final int INTERVAL_ERROR_THRESHOLD = 10;
         int[] defaultFps = new int[2];
         Parameters parameters = mCamera.getParameters();
         parameters.getPreviewFpsRange(defaultFps);
@@ -1919,6 +1920,13 @@
             // See if any frame duration violations occurred during preview run
             AssertionFailedError e = callback.getDurationException();
             if (e != null) throw(e);
+            int numIntervalError = callback.getNumIntervalError();
+            if (numIntervalError > INTERVAL_ERROR_THRESHOLD) {
+                fail(String.format(
+                        "Too many preview callback frame intervals out of bounds: " +
+                                "Count is %d, limit is %d",
+                        numIntervalError, INTERVAL_ERROR_THRESHOLD));
+            }
         }
 
         // Test the invalid fps cases.
@@ -1948,6 +1956,7 @@
         private ArrayList<Long> mFrames = new ArrayList<Long>();
         private long firstFrameArrivalTime;
         private AssertionFailedError mDurationException = null;
+        private int numIntervalError;
 
         public void reset(double minFps, double maxFps) {
             this.mMinFps = minFps;
@@ -1960,6 +1969,7 @@
             mFrames.clear();
             firstFrameArrivalTime = 0;
             mDurationException = null;
+            numIntervalError = 0;
         }
 
         // This method tests if the actual fps is between minimum and maximum.
@@ -1997,18 +2007,15 @@
                 long lastArrivalTime = mFrames.get(mFrames.size() - 1);
                 double interval = arrivalTime - lastArrivalTime;
                 if (VERBOSE) Log.v(TAG, "Frame interval=" + interval);
-                try {
-                    assertTrue("Frame interval (" + interval + "ms) is too " +
-                            "large. mMaxFrameInterval=" +
-                             mMaxFrameInterval + "ms",
-                            interval < mMaxFrameInterval *
-                            (1.0 + intervalMargin));
-                    assertTrue("Frame interval (" + interval + "ms) is too " +
-                            "small. mMinFrameInterval=" +
-                            mMinFrameInterval + "ms",
-                            interval > mMinFrameInterval *
-                            (1.0 - intervalMargin));
 
+                try {
+                    if (interval > mMaxFrameInterval * (1.0 + intervalMargin) ||
+                            interval < mMinFrameInterval * (1.0 - intervalMargin)) {
+                        Log.i(TAG, "Bad frame interval=" + interval + "ms. Out out range " +
+                                mMinFrameInterval * (1.0 - intervalMargin) + "/" +
+                                mMaxFrameInterval * (1.0 + intervalMargin));
+                        numIntervalError++;
+                    }
                     // Check if the fps is within range.
                     double fpsMargin = 0.5; // x100 = percent
                     double avgInterval = (double)(arrivalTime - mFrames.get(0))
@@ -2035,6 +2042,9 @@
         public AssertionFailedError getDurationException() {
             return mDurationException;
         }
+        public int getNumIntervalError() {
+            return numIntervalError;
+        }
     }
 
     private void assertEquals(Size expected, Size actual) {
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/ActivityResultMultiplexedLatch.java b/tests/tests/hardware/src/android/hardware/cts/helpers/ActivityResultMultiplexedLatch.java
index bfc59c4..093a659 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/ActivityResultMultiplexedLatch.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/ActivityResultMultiplexedLatch.java
@@ -16,9 +16,6 @@
 
 package android.hardware.cts.helpers;
 
-import android.app.Activity;
-import android.util.Log;
-
 import java.util.HashMap;
 import java.util.concurrent.CountDownLatch;
 
@@ -53,13 +50,8 @@
          *
          * @return The result code of the Activity executed.
          */
-        public int await() {
-            try {
-                mEntry.latch.await();
-            } catch (InterruptedException e) {
-                Log.e(TAG, "Error waiting for Activity result.", e);
-                return Activity.RESULT_CANCELED;
-            }
+        public int await() throws InterruptedException {
+            mEntry.latch.await();
             return mEntry.resultCode;
         }
 
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/CollectingSensorEventListener.java b/tests/tests/hardware/src/android/hardware/cts/helpers/CollectingSensorEventListener.java
index c11b29f..ca7d133 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/CollectingSensorEventListener.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/CollectingSensorEventListener.java
@@ -64,7 +64,7 @@
      * </p>
      */
     @Override
-    public void waitForEvents(int eventCount) {
+    public void waitForEvents(int eventCount) throws InterruptedException {
         clearEvents();
         super.waitForEvents(eventCount);
     }
@@ -76,7 +76,7 @@
      * </p>
      */
     @Override
-    public void waitForEvents(long duration, TimeUnit timeUnit) {
+    public void waitForEvents(long duration, TimeUnit timeUnit) throws InterruptedException {
         clearEvents();
         super.waitForEvents(duration, timeUnit);
     }
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java
index 1f1b290..a79e5b1 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java
@@ -26,7 +26,7 @@
 /**
  * Set of static helper methods for CTS tests.
  */
-//TODO: Refactor this class into several more well defined helper classes
+//TODO: Refactor this class into several more well defined helper classes, look at StatisticsUtils
 public class SensorCtsHelper {
 
     private static final long NANOS_PER_MILLI = 1000000;
@@ -143,13 +143,9 @@
     /**
      * Helper method to sleep for a given duration.
      */
-    public static void sleep(long duration, TimeUnit timeUnit) {
+    public static void sleep(long duration, TimeUnit timeUnit) throws InterruptedException {
         long durationNs = TimeUnit.NANOSECONDS.convert(duration, timeUnit);
-        try {
-            Thread.sleep(durationNs / NANOS_PER_MILLI, (int) (durationNs % NANOS_PER_MILLI));
-        } catch (InterruptedException e) {
-            // Ignore
-        }
+        Thread.sleep(durationNs / NANOS_PER_MILLI, (int) (durationNs % NANOS_PER_MILLI));
     }
 
     /**
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
index 4505633..9b3a5e4 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
@@ -21,6 +21,7 @@
 import android.hardware.Sensor;
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener2;
+import android.os.SystemClock;
 import android.util.Log;
 
 import java.util.Arrays;
@@ -87,30 +88,20 @@
      */
     @Override
     public void onSensorChanged(SensorEvent event) {
+        mListener.onSensorChanged(event);
+        if (mLogEvents) {
+            Log.v(LOG_TAG, String.format(
+                    "Sensor %d: sensor_timestamp=%dns, received_timestamp=%dns, values=%s",
+                    mEnvironment.getSensor().getType(),
+                    event.timestamp,
+                    SystemClock.elapsedRealtimeNanos(),
+                    Arrays.toString(event.values)));
+        }
+
         CountDownLatch eventLatch = mEventLatch;
         if(eventLatch != null) {
             eventLatch.countDown();
         }
-        mListener.onSensorChanged(event);
-        if (mLogEvents) {
-            StringBuilder valuesSb = new StringBuilder();
-            if (event.values.length == 1) {
-                valuesSb.append(String.format("%.2f", event.values[0]));
-            } else {
-                valuesSb.append("[").append(String.format("%.2f", event.values[0]));
-                for (int i = 1; i < event.values.length; i++) {
-                    valuesSb.append(String.format(", %.2f", event.values[i]));
-                }
-                valuesSb.append("]");
-            }
-
-            Log.v(LOG_TAG, String.format(
-                    "Sensor %d: sensor_timestamp=%d, received_timestamp=%d, values=%s",
-                    mEnvironment.getSensor().getType(),
-                    event.timestamp,
-                    System.nanoTime(),
-                    Arrays.toString(event.values)));
-        }
     }
 
     /**
@@ -139,17 +130,14 @@
      *
      * @throws AssertionError if there was a timeout after {@link #FLUSH_TIMEOUT_US} &micro;s
      */
-    public void waitForFlushComplete() {
+    public void waitForFlushComplete() throws InterruptedException {
         CountDownLatch latch = mFlushLatch;
-        try {
-            if(latch != null) {
-                Assert.assertTrue(
-                        SensorCtsHelper.formatAssertionMessage("WaitForFlush", mEnvironment),
-                        latch.await(FLUSH_TIMEOUT_US, TimeUnit.MICROSECONDS));
-            }
-        } catch(InterruptedException e) {
-            // Ignore
+        if(latch == null) {
+            return;
         }
+        Assert.assertTrue(
+                SensorCtsHelper.formatAssertionMessage("WaitForFlush", mEnvironment),
+                latch.await(FLUSH_TIMEOUT_US, TimeUnit.MICROSECONDS));
     }
 
     /**
@@ -157,15 +145,14 @@
      *
      * @throws AssertionError if there was a timeout after {@link #FLUSH_TIMEOUT_US} &micro;s
      */
-    public void waitForEvents(int eventCount) {
+    public void waitForEvents(int eventCount) throws InterruptedException {
         mEventLatch = new CountDownLatch(eventCount);
         try {
             int rateUs = mEnvironment.getExpectedSamplingPeriodUs();
             // Timeout is 2 * event count * expected period + batch timeout + default wait
-            long timeoutUs = ((2 * eventCount * rateUs)
+            long timeoutUs = (2 * eventCount * rateUs)
                     + mEnvironment.getMaxReportLatencyUs()
-                    + EVENT_TIMEOUT_US);
-
+                    + EVENT_TIMEOUT_US;
             String message = SensorCtsHelper.formatAssertionMessage(
                     "WaitForEvents",
                     mEnvironment,
@@ -173,8 +160,6 @@
                     eventCount,
                     eventCount - mEventLatch.getCount());
             Assert.assertTrue(message, mEventLatch.await(timeoutUs, TimeUnit.MICROSECONDS));
-        } catch(InterruptedException e) {
-            // Ignore
         } finally {
             mEventLatch = null;
         }
@@ -183,7 +168,7 @@
     /**
      * Collect {@link TestSensorEvent} for a specific duration.
      */
-    public void waitForEvents(long duration, TimeUnit timeUnit) {
+    public void waitForEvents(long duration, TimeUnit timeUnit) throws InterruptedException {
         SensorCtsHelper.sleep(duration, timeUnit);
     }
 }
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java
index d72a2ce..dc40ff4 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java
@@ -120,24 +120,22 @@
     /**
      * Wait for a specific number of events.
      */
-    public void waitForEvents(int eventCount) {
+    public void waitForEvents(int eventCount) throws InterruptedException {
         if (mTestSensorEventListener == null) {
             Log.w(LOG_TAG, "No listener registered, returning.");
             return;
         }
-
         mTestSensorEventListener.waitForEvents(eventCount);
     }
 
     /**
      * Wait for a specific duration.
      */
-    public void waitForEvents(long duration, TimeUnit timeUnit) {
+    public void waitForEvents(long duration, TimeUnit timeUnit) throws InterruptedException {
         if (mTestSensorEventListener == null) {
             Log.w(LOG_TAG, "No listener registered, returning.");
             return;
         }
-
         mTestSensorEventListener.waitForEvents(duration, timeUnit);
     }
 
@@ -168,7 +166,6 @@
         if (mTestSensorEventListener == null) {
             return;
         }
-
         mTestSensorEventListener.waitForFlushComplete();
     }
 
@@ -185,7 +182,6 @@
         if (mTestSensorEventListener == null) {
             return;
         }
-
         startFlush();
         waitForFlushCompleted();
     }
@@ -193,12 +189,12 @@
     /**
      * Register a listener, wait for a specific number of events, and then unregister the listener.
      */
-    public void runSensor(TestSensorEventListener listener, int eventCount) {
+    public void runSensor(TestSensorEventListener listener, int eventCount)
+            throws InterruptedException {
         if (mTestSensorEventListener != null) {
             Log.w(LOG_TAG, "Listener already registered, returning.");
             return;
         }
-
         try {
             registerListener(listener);
             waitForEvents(eventCount);
@@ -210,12 +206,12 @@
     /**
      * Register a listener, wait for a specific duration, and then unregister the listener.
      */
-    public void runSensor(TestSensorEventListener listener, long duration, TimeUnit timeUnit) {
+    public void runSensor(TestSensorEventListener listener, long duration, TimeUnit timeUnit)
+            throws InterruptedException {
         if (mTestSensorEventListener != null) {
             Log.w(LOG_TAG, "Listener already registered, returning.");
             return;
         }
-
         try {
             registerListener(listener);
             waitForEvents(duration, timeUnit);
@@ -231,7 +227,7 @@
     public void runSensorAndFlush(
             TestSensorEventListener listener,
             long duration,
-            TimeUnit timeUnit) {
+            TimeUnit timeUnit) throws InterruptedException {
         if (mTestSensorEventListener != null) {
             Log.w(LOG_TAG, "Listener already registered, returning.");
             return;
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java
index 95f1248..88e4954 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java
@@ -72,7 +72,7 @@
      * {@inheritDoc}
      */
     @Override
-    public void execute() {
+    public void execute() throws InterruptedException {
         // Start alarm
         IntentFilter intentFilter = new IntentFilter(ACTION);
         BroadcastReceiver receiver = new BroadcastReceiver() {
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/DelaySensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/DelaySensorOperation.java
index bf43189..b4d1f23 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/DelaySensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/DelaySensorOperation.java
@@ -50,8 +50,8 @@
      * {@inheritDoc}
      */
     @Override
-    public void execute() {
-        sleep(mDelay, mTimeUnit);
+    public void execute() throws InterruptedException {
+        SensorCtsHelper.sleep(mDelay, mTimeUnit);
         mOperation.execute();
     }
 
@@ -70,11 +70,4 @@
     public DelaySensorOperation clone() {
         return new DelaySensorOperation(mOperation.clone(), mDelay, mTimeUnit);
     }
-
-    /**
-     * Helper method to sleep for a given number of ns. Exposed for unit testing.
-     */
-    void sleep(long delay, TimeUnit timeUnit) {
-        SensorCtsHelper.sleep(delay, timeUnit);
-    }
 }
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ISensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ISensorOperation.java
index 4ae56ea..62a4e9e 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ISensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ISensorOperation.java
@@ -38,8 +38,12 @@
     /**
      * Executes the sensor operation.  This may throw {@link RuntimeException}s such as
      * {@link AssertionError}s.
+     *
+     * NOTE: the operation is expected to handle interruption by:
+     * - cleaning up on {@link InterruptedException}
+     * - propagating the exception down the stack
      */
-    public void execute();
+    public void execute() throws InterruptedException;
 
     /**
      * Get the stats for the operation.
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ParallelSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ParallelSensorOperation.java
index 4cca428..5a4466c 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ParallelSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ParallelSensorOperation.java
@@ -16,15 +16,21 @@
 
 package android.hardware.cts.helpers.sensoroperations;
 
-import android.hardware.cts.helpers.SensorStats;
-import android.util.Log;
-
 import junit.framework.Assert;
 
+import android.hardware.cts.helpers.SensorStats;
+import android.os.SystemClock;
+
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * A {@link ISensorOperation} that executes a set of children {@link ISensorOperation}s in parallel.
@@ -34,9 +40,6 @@
 public class ParallelSensorOperation extends AbstractSensorOperation {
     public static final String STATS_TAG = "parallel";
 
-    private static final String TAG = "ParallelSensorOperation";
-    private static final int NANOS_PER_MILLI = 1000000;
-
     private final List<ISensorOperation> mOperations = new LinkedList<ISensorOperation>();
     private final Long mTimeout;
     private final TimeUnit mTimeUnit;
@@ -44,6 +47,7 @@
     /**
      * Constructor for the {@link ParallelSensorOperation} without a timeout.
      */
+    // TODO: sensor tests must always provide a timeout to prevent tests from running forever
     public ParallelSensorOperation() {
         mTimeout = null;
         mTimeUnit = null;
@@ -77,57 +81,67 @@
      * operations, the first exception will be thrown once all operations are completed.
      */
     @Override
-    public void execute() {
-        Long timeoutTimeNs = null;
-        if (mTimeout != null && mTimeUnit != null) {
-            timeoutTimeNs = System.nanoTime() + TimeUnit.NANOSECONDS.convert(mTimeout, mTimeUnit);
-        }
+    public void execute() throws InterruptedException {
+        int operationsCount = mOperations.size();
+        ThreadPoolExecutor executor = new ThreadPoolExecutor(
+                operationsCount,
+                operationsCount,
+                1 /* keepAliveTime */,
+                TimeUnit.SECONDS,
+                new LinkedBlockingQueue<Runnable>());
+        executor.allowCoreThreadTimeOut(true);
+        executor.prestartAllCoreThreads();
 
-        List<OperationThread> threadPool = new ArrayList<OperationThread>(mOperations.size());
+        ArrayList<Future<ISensorOperation>> futures = new ArrayList<Future<ISensorOperation>>();
         for (final ISensorOperation operation : mOperations) {
-            OperationThread thread = new OperationThread(operation);
-            thread.start();
-            threadPool.add(thread);
+            Future<ISensorOperation> future = executor.submit(new Callable<ISensorOperation>() {
+                @Override
+                public ISensorOperation call() throws Exception {
+                    operation.execute();
+                    return operation;
+                }
+            });
+            futures.add(future);
         }
 
-        List<Integer> timeoutIndices = new ArrayList<Integer>();
-        List<OperationExceptionInfo> exceptions = new ArrayList<OperationExceptionInfo>();
-        Throwable earliestException = null;
-        Long earliestExceptionTime = null;
+        Long executionTimeNs = null;
+        if (mTimeout != null) {
+            executionTimeNs = SystemClock.elapsedRealtimeNanos()
+                    + TimeUnit.NANOSECONDS.convert(mTimeout, mTimeUnit);
+        }
 
-        for (int i = 0; i < threadPool.size(); i++) {
-            OperationThread thread = threadPool.get(i);
-            join(thread, timeoutTimeNs);
-            if (thread.isAlive()) {
+        boolean hasAssertionErrors = false;
+        ArrayList<Integer> timeoutIndices = new ArrayList<Integer>();
+        ArrayList<Throwable> exceptions = new ArrayList<Throwable>();
+        for (int i = 0; i < operationsCount; ++i) {
+            Future<ISensorOperation> future = futures.get(i);
+            try {
+                ISensorOperation operation = getFutureResult(future, executionTimeNs);
+                addSensorStats(STATS_TAG, i, operation.getStats());
+            } catch (ExecutionException e) {
+                // extract the exception thrown by the worker thread
+                Throwable cause = e.getCause();
+                hasAssertionErrors |= (cause instanceof AssertionError);
+                exceptions.add(e.getCause());
+                addSensorStats(STATS_TAG, i, mOperations.get(i).getStats());
+            } catch (TimeoutException e) {
+                // we log, but we also need to interrupt the operation to terminate cleanly
                 timeoutIndices.add(i);
-                thread.interrupt();
+                future.cancel(true /* mayInterruptIfRunning */);
+            } catch (InterruptedException e) {
+                // clean-up after ourselves by interrupting all the worker threads, and propagate
+                // the interruption status, so we stop the outer loop as well
+                executor.shutdownNow();
+                throw e;
             }
-
-            Throwable exception = thread.getException();
-            Long exceptionTime = thread.getExceptionTime();
-            if (exception != null && exceptionTime != null) {
-                if (exception instanceof AssertionError) {
-                    exceptions.add(new OperationExceptionInfo(i, (AssertionError) exception));
-                }
-                if (earliestExceptionTime == null || exceptionTime < earliestExceptionTime) {
-                    earliestException = exception;
-                    earliestExceptionTime = exceptionTime;
-                }
-            }
-
-            addSensorStats(STATS_TAG, i, thread.getSensorOperation().getStats());
         }
 
-        if (earliestException == null) {
-            if (timeoutIndices.size() > 0) {
-                Assert.fail(getTimeoutMessage(timeoutIndices));
-            }
-        } else if (earliestException instanceof AssertionError) {
-            String msg = getExceptionMessage(exceptions, timeoutIndices);
-            getStats().addValue(SensorStats.ERROR, msg);
-            throw new AssertionError(msg, earliestException);
-        } else if (earliestException instanceof RuntimeException) {
-            throw (RuntimeException) earliestException;
+        String summary = getSummaryMessage(exceptions, timeoutIndices);
+        if (hasAssertionErrors) {
+            getStats().addValue(SensorStats.ERROR, summary);
+        }
+        if (!exceptions.isEmpty() || !timeoutIndices.isEmpty()) {
+            Assert.fail(summary);
         }
     }
 
@@ -144,114 +158,39 @@
     }
 
     /**
-     * Helper method that joins a thread at a given time in the future.
+     * Helper method that waits for a {@link Future} to complete, and returns its result.
      */
-    private void join(Thread thread, Long timeoutTimeNs) {
-        try {
-            if (timeoutTimeNs == null) {
-                thread.join();
-            } else {
-                // Cap wait time to 1ns so that join doesn't block indefinitely.
-                long waitTimeNs = Math.max(timeoutTimeNs - System.nanoTime(), 1);
-                thread.join(waitTimeNs / NANOS_PER_MILLI, (int) waitTimeNs % NANOS_PER_MILLI);
-            }
-        } catch (InterruptedException e) {
-            // Log and ignore
-            Log.w(TAG, "Thread interrupted during join, operations may timeout before expected"
-                    + " time");
+    private ISensorOperation getFutureResult(Future<ISensorOperation> future, Long timeoutNs)
+            throws ExecutionException, TimeoutException, InterruptedException {
+        if (timeoutNs == null) {
+            return future.get();
         }
+        // cap timeout to 1ns so that join doesn't block indefinitely
+        long waitTimeNs = Math.max(timeoutNs - SystemClock.elapsedRealtimeNanos(), 1);
+        return future.get(waitTimeNs, TimeUnit.NANOSECONDS);
     }
 
     /**
-     * Helper method for joining the exception messages used in assertions.
+     * Helper method for joining the exception and timeout messages used in assertions.
      */
-    private String getExceptionMessage(List<OperationExceptionInfo> exceptions,
-            List<Integer> timeoutIndices) {
+    private String getSummaryMessage(List<Throwable> exceptions, List<Integer> timeoutIndices) {
         StringBuilder sb = new StringBuilder();
-        sb.append(exceptions.get(0).toString());
-        for (int i = 1; i < exceptions.size(); i++) {
-            sb.append(", ").append(exceptions.get(i).toString());
-        }
-        if (timeoutIndices.size() > 0) {
-            sb.append(", ").append(getTimeoutMessage(timeoutIndices));
-        }
-        return sb.toString();
-    }
-
-    /**
-     * Helper method for formatting the operation timed out message used in assertions
-     */
-    private String getTimeoutMessage(List<Integer> indices) {
-        StringBuilder sb = new StringBuilder();
-        sb.append("Operation");
-        if (indices.size() != 1) {
-            sb.append("s");
-        }
-        sb.append(" ").append(indices.get(0));
-        for (int i = 1; i < indices.size(); i++) {
-            sb.append(", ").append(indices.get(i));
-        }
-        sb.append(" timed out");
-        return sb.toString();
-    }
-
-    /**
-     * Helper class for holding operation index and exception
-     */
-    private class OperationExceptionInfo {
-        private final int mIndex;
-        private final AssertionError mException;
-
-        public OperationExceptionInfo(int index, AssertionError exception) {
-            mIndex = index;
-            mException = exception;
+        for (Throwable exception : exceptions) {
+            sb.append(exception.toString()).append(", ");
         }
 
-        @Override
-        public String toString() {
-            return String.format("Operation %d failed: \"%s\"", mIndex, mException.getMessage());
-        }
-    }
-
-    /**
-     * Helper class to run the {@link ISensorOperation} in its own thread.
-     */
-    private class OperationThread extends Thread {
-        final private ISensorOperation mOperation;
-        private Throwable mException = null;
-        private Long mExceptionTime = null;
-
-        public OperationThread(ISensorOperation operation) {
-            mOperation = operation;
-        }
-
-        /**
-         * Run the thread catching {@link RuntimeException}s and {@link AssertionError}s and
-         * the time it happened.
-         */
-        @Override
-        public void run() {
-            try {
-                mOperation.execute();
-            } catch (AssertionError e) {
-                mExceptionTime = System.nanoTime();
-                mException = e;
-            } catch (RuntimeException e) {
-                mExceptionTime = System.nanoTime();
-                mException = e;
+        if (!timeoutIndices.isEmpty()) {
+            sb.append("Operation");
+            if (timeoutIndices.size() != 1) {
+                sb.append("s");
             }
+            sb.append(" [");
+            for (Integer index : timeoutIndices) {
+                sb.append(index).append(", ");
+            }
+            sb.append("] timed out");
         }
 
-        public ISensorOperation getSensorOperation() {
-            return mOperation;
-        }
-
-        public Throwable getException() {
-            return mException;
-        }
-
-        public Long getExceptionTime() {
-            return mExceptionTime;
-        }
+        return sb.toString();
     }
 }
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/RepeatingSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/RepeatingSensorOperation.java
index 5e023e5..3d682fe 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/RepeatingSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/RepeatingSensorOperation.java
@@ -48,7 +48,7 @@
      * in one iterations, it is thrown and all subsequent iterations will not run.
      */
     @Override
-    public void execute() {
+    public void execute() throws InterruptedException {
         for(int i = 0; i < mIterations; ++i) {
             ISensorOperation operation = mOperation.clone();
             try {
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperationTest.java
index 15b6978..bc48725 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperationTest.java
@@ -35,7 +35,7 @@
      * Test that the {@link FakeSensorOperation} functions correctly. Other tests in this class
      * rely on this operation.
      */
-    public void testFakeSensorOperation() {
+    public void testFakeSensorOperation() throws InterruptedException {
         final int opDurationMs = 100;
 
         ISensorOperation op = new FakeSensorOperation(opDurationMs, TimeUnit.MILLISECONDS);
@@ -60,7 +60,7 @@
     /**
      * Test that the {@link DelaySensorOperation} functions correctly.
      */
-    public void testDelaySensorOperation() {
+    public void testDelaySensorOperation() throws InterruptedException {
         final int opDurationMs = 500;
         final int subOpDurationMs = 100;
 
@@ -77,7 +77,7 @@
     /**
      * Test that the {@link ParallelSensorOperation} functions correctly.
      */
-    public void testParallelSensorOperation() {
+    public void testParallelSensorOperation() throws InterruptedException {
         final int subOpCount = 100;
         final int subOpDurationMs = 500;
 
@@ -118,7 +118,7 @@
      * Test that the {@link ParallelSensorOperation} functions correctly if there is a failure in
      * a child operation.
      */
-    public void testParallelSensorOperation_fail() {
+    public void testParallelSensorOperation_fail() throws InterruptedException {
         final int subOpCount = 100;
 
         ParallelSensorOperation op = new ParallelSensorOperation();
@@ -158,7 +158,7 @@
      * Test that the {@link ParallelSensorOperation} functions correctly if a child exceeds the
      * timeout.
      */
-    public void testParallelSensorOperation_timeout() {
+    public void testParallelSensorOperation_timeout() throws InterruptedException {
         final int subOpCount = 100;
 
         ParallelSensorOperation op = new ParallelSensorOperation(1, TimeUnit.SECONDS);
@@ -192,7 +192,7 @@
     /**
      * Test that the {@link RepeatingSensorOperation} functions correctly.
      */
-    public void testRepeatingSensorOperation() {
+    public void testRepeatingSensorOperation() throws InterruptedException {
         final int iterations = 10;
         final int subOpDurationMs = 100;
 
@@ -219,7 +219,7 @@
      * Test that the {@link RepeatingSensorOperation} functions correctly if there is a failure in
      * a child operation.
      */
-    public void testRepeatingSensorOperation_fail() {
+    public void testRepeatingSensorOperation_fail() throws InterruptedException {
         final int iterations = 100;
         final int failCount = 75;
 
@@ -277,7 +277,7 @@
     /**
      * Test that the {@link SequentialSensorOperation} functions correctly.
      */
-    public void testSequentialSensorOperation() {
+    public void testSequentialSensorOperation() throws InterruptedException {
         final int subOpCount = 10;
         final int subOpDurationMs = 100;
 
@@ -308,7 +308,7 @@
      * Test that the {@link SequentialSensorOperation} functions correctly if there is a failure in
      * a child operation.
      */
-    public void testSequentialSensorOperation_fail() {
+    public void testSequentialSensorOperation_fail() throws InterruptedException {
         final int subOpCount = 100;
         final int failCount = 75;
 
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SequentialSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SequentialSensorOperation.java
index 050a8f6..2ed0ca6 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SequentialSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SequentialSensorOperation.java
@@ -48,7 +48,7 @@
      * in one operation, it is thrown and all subsequent operations will not run.
      */
     @Override
-    public void execute() {
+    public void execute() throws InterruptedException {
         for (int i = 0; i < mOperations.size(); i++) {
             ISensorOperation operation = mOperations.get(i);
             try {
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorFlushOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorFlushOperation.java
index 1fb6bef..d5aa4b9 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorFlushOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorFlushOperation.java
@@ -53,7 +53,7 @@
      * {@inheritDoc}
      */
     @Override
-    protected void doExecute(TestSensorEventListener listener) {
+    protected void doExecute(TestSensorEventListener listener) throws InterruptedException {
         mSensorManager.runSensorAndFlush(listener, mDuration, mTimeUnit);
     }
 
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
index 6c3851e..695e1a7 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
@@ -76,7 +76,7 @@
      * {@inheritDoc}
      */
     @Override
-    protected void doExecute(TestSensorEventListener listener) {
+    protected void doExecute(TestSensorEventListener listener) throws InterruptedException {
         if (mEventCount != null) {
             mSensorManager.runSensor(listener, mEventCount);
         } else {
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/VerifiableSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/VerifiableSensorOperation.java
index c635a75..57018eb 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/VerifiableSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/VerifiableSensorOperation.java
@@ -94,7 +94,7 @@
      * Collect the specified number of events from the sensor and run all enabled verifications.
      */
     @Override
-    public void execute() {
+    public void execute() throws InterruptedException {
         getStats().addValue("sensor_name", mEnvironment.getSensor().getName());
 
         ValidatingSensorEventListener listener = new ValidatingSensorEventListener(mVerifications);
@@ -131,7 +131,7 @@
     /**
      * Execute operations in a {@link TestSensorManager}.
      */
-    protected abstract void doExecute(TestSensorEventListener listener);
+    protected abstract void doExecute(TestSensorEventListener listener) throws InterruptedException;
 
     /**
      * Clone the subclass operation.
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/WakeLockOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/WakeLockOperation.java
index 73da9c9..b500ea7 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/WakeLockOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/WakeLockOperation.java
@@ -59,7 +59,7 @@
      * {@inheritDoc}
      */
     @Override
-    public void execute() {
+    public void execute() throws InterruptedException {
         PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         WakeLock wakeLock = pm.newWakeLock(mWakelockFlags, TAG);
 
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyChainTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyChainTest.java
index db6d6ba..7aa6a9d 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyChainTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyChainTest.java
@@ -16,10 +16,11 @@
 
 package android.keystore.cts;
 
+import android.content.pm.PackageManager;
 import android.security.KeyChain;
-import junit.framework.TestCase;
+import android.test.AndroidTestCase;
 
-public class KeyChainTest extends TestCase {
+public class KeyChainTest extends AndroidTestCase {
     public void testIsKeyAlgorithmSupported_RequiredAlgorithmsSupported() throws Exception {
         assertTrue("DSA must be supported", KeyChain.isKeyAlgorithmSupported("DSA"));
         assertTrue("EC must be supported", KeyChain.isKeyAlgorithmSupported("EC"));
@@ -34,11 +35,21 @@
      * tests in hardware/libhardware/tests/keymaster/
      */
     public void testIsBoundKeyAlgorithm_RequiredAlgorithmsSupported() throws Exception {
-        assertTrue("RSA must be hardware-backed by a hardware-specific Keymaster HAL",
-                KeyChain.isBoundKeyAlgorithm("RSA"));
+        if (isLeanbackOnly()) {
+            KeyChain.isBoundKeyAlgorithm("RSA");
+        }
+        else {
+            assertTrue("RSA must be hardware-backed by a hardware-specific Keymaster HAL",
+                       KeyChain.isBoundKeyAlgorithm("RSA"));
+        }
 
         // These are not required, but must not throw an exception
         KeyChain.isBoundKeyAlgorithm("DSA");
         KeyChain.isBoundKeyAlgorithm("EC");
     }
+
+    private boolean isLeanbackOnly() {
+        PackageManager pm = getContext().getPackageManager();
+        return (pm != null && pm.hasSystemFeature("android.software.leanback_only"));
+    }
 }
diff --git a/tests/tests/location2/src/android/location2/cts/LocationManagerTest.java b/tests/tests/location2/src/android/location2/cts/LocationManagerTest.java
index f330e8a..3765809 100644
--- a/tests/tests/location2/src/android/location2/cts/LocationManagerTest.java
+++ b/tests/tests/location2/src/android/location2/cts/LocationManagerTest.java
@@ -227,15 +227,18 @@
     @UiThreadTest
     public void testGpsStatusListener() {
         try {
-            mManager.addGpsStatusListener(new MockGpsStatusListener());
-            fail("Should have failed to add a gps status listener");
+            // .addGpsStatusListener returns true if the listener added successfully
+            if (mManager.addGpsStatusListener(new MockGpsStatusListener())) {
+                fail("Should have failed to add a gps status listener");
+            }
         } catch (SecurityException e) {
             // expected
         }
 
         try {
-            mManager.addGpsStatusListener(null);
-            fail("Should have failed to add a gps status listener");
+            if (mManager.addGpsStatusListener(null)) {
+                fail("Should have failed to add null as a gps status listener");
+            }
         } catch (SecurityException e) {
             // expected
         }
diff --git a/tests/tests/media/libmediandkjni/native-media-jni.cpp b/tests/tests/media/libmediandkjni/native-media-jni.cpp
index 51d2cf2..850932f1 100644
--- a/tests/tests/media/libmediandkjni/native-media-jni.cpp
+++ b/tests/tests/media/libmediandkjni/native-media-jni.cpp
@@ -590,14 +590,14 @@
         return false;
     }
 
-    ALOGI("pssh has %u entries", info->numentries);
+    ALOGI("pssh has %zd entries", info->numentries);
     if (info->numentries != 2) {
         return false;
     }
 
     for (size_t i = 0; i < info->numentries; i++) {
         PsshEntry *entry = &info->entries[i];
-        ALOGI("entry uuid %02x%02x..%02x%02x, data size %u",
+        ALOGI("entry uuid %02x%02x..%02x%02x, data size %zd",
                 entry->uuid[0],
                 entry->uuid[1],
                 entry->uuid[14],
diff --git a/tests/tests/media/res/raw/heap_oob_flac.mp3 b/tests/tests/media/res/raw/heap_oob_flac.mp3
new file mode 100644
index 0000000..ae542d0
--- /dev/null
+++ b/tests/tests/media/res/raw/heap_oob_flac.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/midi8sec.mid b/tests/tests/media/res/raw/midi8sec.mid
new file mode 100644
index 0000000..746aca1
--- /dev/null
+++ b/tests/tests/media/res/raw/midi8sec.mid
Binary files differ
diff --git a/tests/tests/media/res/raw/midi_a.mid b/tests/tests/media/res/raw/midi_a.mid
new file mode 100644
index 0000000..941885f
--- /dev/null
+++ b/tests/tests/media/res/raw/midi_a.mid
Binary files differ
diff --git a/tests/tests/media/res/raw/midi_b.mid b/tests/tests/media/res/raw/midi_b.mid
new file mode 100644
index 0000000..424c960
--- /dev/null
+++ b/tests/tests/media/res/raw/midi_b.mid
Binary files differ
diff --git a/tests/tests/media/res/raw/midi_cs.mid b/tests/tests/media/res/raw/midi_cs.mid
new file mode 100644
index 0000000..ee9cb23
--- /dev/null
+++ b/tests/tests/media/res/raw/midi_cs.mid
Binary files differ
diff --git a/tests/tests/media/res/raw/midi_e.mid b/tests/tests/media/res/raw/midi_e.mid
new file mode 100644
index 0000000..dac820d
--- /dev/null
+++ b/tests/tests/media/res/raw/midi_e.mid
Binary files differ
diff --git a/tests/tests/media/res/raw/midi_gs.mid b/tests/tests/media/res/raw/midi_gs.mid
new file mode 100644
index 0000000..1d43841
--- /dev/null
+++ b/tests/tests/media/res/raw/midi_gs.mid
Binary files differ
diff --git a/tests/tests/media/src/android/media/cts/AudioEffectTest.java b/tests/tests/media/src/android/media/cts/AudioEffectTest.java
index 7ff78d8..1c96abd 100644
--- a/tests/tests/media/src/android/media/cts/AudioEffectTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioEffectTest.java
@@ -35,10 +35,10 @@
 import android.util.Log;
 import java.util.UUID;
 
-public class AudioEffectTest extends AndroidTestCase {
+public class AudioEffectTest extends PostProcTestBase {
 
     private String TAG = "AudioEffectTest";
-    private final static int MIN_NUMBER_EFFECTS = 5;
+    private final static int MIN_NUMBER_EFFECTS = 1;
     // allow +/- 5% tolerance between set and get delays
     private final static float DELAY_TOLERANCE = 1.05f;
     // allow +/- 5% tolerance between set and get ratios
@@ -50,17 +50,9 @@
 
     private AudioEffect mEffect = null;
     private AudioEffect mEffect2 = null;
-    private int mSession = -1;
-    private boolean mHasControl = false;
-    private boolean mIsEnabled = false;
-    private int mChangedParameter = -1;
-    private boolean mInitialized = false;
-    private Looper mLooper = null;
     private MediaPlayer mMediaPlayer = null;
     private int mError = 0;
 
-    private final Object mLock = new Object();
-
     private ListenerThread mEffectListenerLooper = null;
 
     //-----------------------------------------------------------------
@@ -71,9 +63,11 @@
     // 0 - static methods
     //----------------------------------
 
-    //Test case 0.0: test queryEffects() and platfrom at least provides Equalizer, Bass Boost,
-    // Virtualizer, Environmental reverb and Preset reverb effects
+    //Test case 0.0: test queryEffects() and platfrom at least provides an Equalizer
     public void test0_0QueryEffects() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
 
         AudioEffect.Descriptor[] desc = AudioEffect.queryEffects();
 
@@ -81,29 +75,14 @@
                 (desc.length >= MIN_NUMBER_EFFECTS));
 
         boolean hasEQ = false;
-        boolean hasBassBoost = false;
-        boolean hasVirtualizer = false;
-        boolean hasEnvReverb = false;
-        boolean hasPresetReverb = false;
 
         for (int i = 0; i < desc.length; i++) {
             if (desc[i].type.equals(AudioEffect.EFFECT_TYPE_EQUALIZER)) {
                 hasEQ = true;
-            } else if (desc[i].type.equals(AudioEffect.EFFECT_TYPE_BASS_BOOST)) {
-                hasBassBoost = true;
-            } else if (desc[i].type.equals(AudioEffect.EFFECT_TYPE_VIRTUALIZER)) {
-                hasVirtualizer = true;
-            } else if (desc[i].type.equals(AudioEffect.EFFECT_TYPE_ENV_REVERB)) {
-                hasEnvReverb = true;
-            } else if (desc[i].type.equals(AudioEffect.EFFECT_TYPE_PRESET_REVERB)) {
-                hasPresetReverb = true;
+                break;
             }
         }
         assertTrue("test0_0QueryEffects: equalizer not found", hasEQ);
-        assertTrue("test0_0QueryEffects: bass boost not found", hasBassBoost);
-        assertTrue("test0_0QueryEffects: virtualizer not found", hasVirtualizer);
-        assertTrue("test0_0QueryEffects: environmental reverb not found", hasEnvReverb);
-        assertTrue("test0_0QueryEffects: preset reverb not found", hasPresetReverb);
     }
 
     //-----------------------------------------------------------------
@@ -129,45 +108,10 @@
         return ar;
     }
 
-    //Test case 1.0: test constructor from effect type and get effect ID
-    public void test1_0ConstructorFromType() throws Exception {
-        AudioEffect.Descriptor[] desc = AudioEffect.queryEffects();
-        assertTrue("no effects found", (desc.length != 0));
-        for (int i = 0; i < desc.length; i++) {
-            if (!desc[i].type.equals(AudioEffect.EFFECT_TYPE_NULL)) {
-                try {
-                    int sessionId;
-                    AudioRecord ar = null;
-                    if (AudioEffect.EFFECT_PRE_PROCESSING.equals(desc[i].connectMode)) {
-                        ar = getAudioRecord();
-                        sessionId = ar.getAudioSessionId();
-                    } else {
-                        sessionId = 0;
-                    }
-                    AudioEffect effect = new AudioEffect(desc[i].type,
-                            AudioEffect.EFFECT_TYPE_NULL,
-                            0,
-                            sessionId);
+//    // Test case 1.0: test constructor from effect type and get effect ID
+//    public void test1_0ConstructorFromType() ...
+//    Note: This test was removed because it used hidden api's.
 
-                    assertNotNull("could not create AudioEffect", effect);
-                    try {
-                        assertTrue("invalid effect ID", (effect.getId() != 0));
-                    } catch (IllegalStateException e) {
-                        fail("AudioEffect not initialized");
-                    } finally {
-                        effect.release();
-                        if (ar != null) {
-                            ar.release();
-                        }
-                    }
-                } catch (IllegalArgumentException e) {
-                    fail("Effect not found: "+desc[i].name);
-                } catch (UnsupportedOperationException e) {
-                    fail("Effect library not loaded");
-                }
-            }
-        }
-    }
 
 //    //Test case 1.1: test constructor from effect uuid
 //    public void test1_1ConstructorFromUuid() ...
@@ -175,28 +119,15 @@
 //     1. will fail in devices that offload effects
 //     2. it used hidden api's.
 
-    //Test case 1.2: test constructor failure from unknown type
-    public void test1_2ConstructorUnknownType() throws Exception {
-
-        try {
-            AudioEffect effect = new AudioEffect(UUID.randomUUID(),
-                    AudioEffect.EFFECT_TYPE_NULL,
-                    0,
-                    0);
-            fail("could create random AudioEffect");
-            if (effect != null) {
-                effect.release();
-            }
-        } catch (IllegalArgumentException e) {
-
-        } catch (UnsupportedOperationException e) {
-            fail("Effect library not loaded");
-        }
-    }
+//    //Test case 1.2: test constructor failure from unknown type
+//    public void test1_2ConstructorUnknownType() ...
+//    Note: This test was removed because it used hidden api's.
 
     //Test case 1.3: test getEnabled() failure when called on released effect
     public void test1_3GetEnabledAfterRelease() throws Exception {
-
+        if (!hasAudioOutput()) {
+            return;
+        }
         try {
             AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
                     AudioEffect.EFFECT_TYPE_NULL,
@@ -219,6 +150,9 @@
 
     //Test case 1.4: test contructor on mediaPlayer audio session
     public void test1_4InsertOnMediaPlayer() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
         MediaPlayer mp = new MediaPlayer();
         assertNotNull("could not create mediaplayer", mp);
         AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(R.raw.testmp3);
@@ -238,6 +172,9 @@
 
     //Test case 1.5: test auxiliary effect attachement on MediaPlayer
     public void test1_5AuxiliaryOnMediaPlayer() throws Exception {
+        if (!isPresetReverbAvailable()) {
+            return;
+        }
         synchronized(mLock) {
             mInitialized = false;
             createMediaPlayerLooper();
@@ -270,6 +207,9 @@
 
     //Test case 1.6: test auxiliary effect attachement failure before setDatasource
     public void test1_6AuxiliaryOnMediaPlayerFailure() throws Exception {
+        if (!isPresetReverbAvailable()) {
+            return;
+        }
         synchronized(mLock) {
             mInitialized = false;
             createMediaPlayerLooper();
@@ -301,6 +241,9 @@
 
     //Test case 1.7: test auxiliary effect attachement on AudioTrack
     public void test1_7AuxiliaryOnAudioTrack() throws Exception {
+        if (!isPresetReverbAvailable()) {
+            return;
+        }
         AudioTrack track = null;
         getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
         try {
@@ -342,7 +285,9 @@
 
     //Test case 2.0: test setEnabled() and getEnabled() in valid state
     public void test2_0SetEnabledGetEnabled() throws Exception {
-
+        if (!hasAudioOutput()) {
+            return;
+        }
         try {
             AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
                     AudioEffect.EFFECT_TYPE_NULL,
@@ -370,7 +315,9 @@
 
     //Test case 2.1: test setEnabled() throws exception after release
     public void test2_1SetEnabledAfterRelease() throws Exception {
-
+        if (!hasAudioOutput()) {
+            return;
+        }
         try {
             AudioEffect effect = new AudioEffect(AudioEffect.EFFECT_TYPE_EQUALIZER,
                     AudioEffect.EFFECT_TYPE_NULL,
@@ -397,6 +344,9 @@
 
     //Test case 3.0: test setParameter(byte[], byte[]) / getParameter(byte[], byte[])
     public void test3_0SetParameterByteArrayByteArray() throws Exception {
+        if (!isPresetReverbAvailable()) {
+            return;
+        }
         getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
         try {
             byte[] param = mEffect.intToByteArray(PresetReverb.PARAM_PRESET);
@@ -428,6 +378,9 @@
 
     //Test case 3.1: test setParameter(int, int) / getParameter(int, int[])
     public void test3_1SetParameterIntInt() throws Exception {
+        if (!isEnvReverbAvailable()) {
+            return;
+        }
         getEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB, 0);
         try {
             int param = EnvironmentalReverb.PARAM_DECAY_TIME;
@@ -459,6 +412,9 @@
 
     //Test case 3.2: test setParameter(int, short) / getParameter(int, short[])
     public void test3_2SetParameterIntShort() throws Exception {
+        if (!isPresetReverbAvailable()) {
+            return;
+        }
         getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
         try {
             int param = PresetReverb.PARAM_PRESET;
@@ -488,6 +444,9 @@
 
     //Test case 3.3: test setParameter(int, byte[]) / getParameter(int, byte[])
     public void test3_3SetParameterIntByteArray() throws Exception {
+        if (!isEnvReverbAvailable()) {
+            return;
+        }
         getEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB, 0);
         try {
             int param = EnvironmentalReverb.PARAM_DECAY_TIME;
@@ -521,6 +480,9 @@
 
     //Test case 3.4: test setParameter(int[], int[]) / getParameter(int[], int[])
     public void test3_4SetParameterIntArrayIntArray() throws Exception {
+        if (!isEnvReverbAvailable()) {
+            return;
+        }
         getEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB, 0);
         try {
             int[] param = new int[1];
@@ -555,6 +517,9 @@
     //Test case 3.5: test setParameter(int[], short[]) / getParameter(int[], short[])
 
     public void test3_5SetParameterIntArrayShortArray() throws Exception {
+        if (!isPresetReverbAvailable()) {
+            return;
+        }
         getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
         try {
             int[] param = new int[1];
@@ -586,6 +551,9 @@
 
     //Test case 3.6: test setParameter(int[], byte[]) / getParameter(int[], byte[])
     public void test3_6SetParameterIntArrayByteArray() throws Exception {
+        if (!isEnvReverbAvailable()) {
+            return;
+        }
         getEffect(AudioEffect.EFFECT_TYPE_ENV_REVERB, 0);
         try {
             int[] param = new int[1];
@@ -620,6 +588,9 @@
 
     //Test case 3.7: test setParameter() throws exception after release()
     public void test3_7SetParameterAfterRelease() throws Exception {
+        if (!isPresetReverbAvailable()) {
+            return;
+        }
         AudioEffect effect = null;
         try {
             effect = new AudioEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB,
@@ -645,6 +616,9 @@
 
     //Test case 3.8: test getParameter() throws exception after release()
     public void test3_8GetParameterAfterRelease() throws Exception {
+        if (!isPresetReverbAvailable()) {
+            return;
+        }
         AudioEffect effect = null;
         try {
             effect = new AudioEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB,
@@ -675,6 +649,9 @@
 
     //Test case 4.0: test control passed to higher priority client
     public void test4_0setEnabledLowerPriority() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
         AudioEffect effect1 = null;
         AudioEffect effect2 = null;
         try {
@@ -712,6 +689,9 @@
 
     //Test case 4.1: test control passed to higher priority client
     public void test4_1setParameterLowerPriority() throws Exception {
+        if (!isPresetReverbAvailable()) {
+            return;
+        }
         AudioEffect effect1 = null;
         AudioEffect effect2 = null;
         try {
@@ -761,7 +741,9 @@
 
     //Test case 4.2: test control status listener
     public void test4_2ControlStatusListener() throws Exception {
-
+        if (!isPresetReverbAvailable()) {
+            return;
+        }
         synchronized(mLock) {
             mHasControl = true;
             mInitialized = false;
@@ -784,7 +766,9 @@
 
     //Test case 4.3: test enable status listener
     public void test4_3EnableStatusListener() throws Exception {
-
+        if (!isPresetReverbAvailable()) {
+            return;
+        }
         synchronized(mLock) {
             mInitialized = false;
             createListenerLooper(false, true, false);
@@ -811,6 +795,9 @@
 
     //Test case 4.4: test parameter changed listener
     public void test4_4ParameterChangedListener() throws Exception {
+        if (!isPresetReverbAvailable()) {
+            return;
+        }
         synchronized(mLock) {
             mInitialized = false;
             createListenerLooper(false, false, true);
@@ -844,6 +831,9 @@
 
     //Test case 5.0: test command method
     public void test5_0Command() throws Exception {
+        if (!isPresetReverbAvailable()) {
+            return;
+        }
         getEffect(AudioEffect.EFFECT_TYPE_PRESET_REVERB, 0);
         try {
             byte[] cmd = new byte[0];
diff --git a/tests/tests/media/src/android/media/cts/AudioPreProcessingTest.java b/tests/tests/media/src/android/media/cts/AudioPreProcessingTest.java
index e993695..de5b698 100644
--- a/tests/tests/media/src/android/media/cts/AudioPreProcessingTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioPreProcessingTest.java
@@ -18,6 +18,7 @@
 
 import com.android.cts.media.R;
 
+import android.content.pm.PackageManager;
 import android.media.AudioFormat;
 import android.media.AudioRecord;
 import android.media.audiofx.AcousticEchoCanceler;
@@ -47,6 +48,10 @@
 
     //Test case 1.1: test NS creation and release
     public void test1_1NsCreateAndRelease() throws Exception {
+        if (!hasMicrophone()) {
+            return;
+        }
+
         AudioRecord ar = getAudioRecord();
         assertNotNull("could not create AudioRecord", ar);
 
@@ -67,6 +72,10 @@
 
     //Test case 1.2: test setEnabled() and getEnabled()
     public void test1_2NsSetEnabledGetEnabled() throws Exception {
+        if (!hasMicrophone()) {
+            return;
+        }
+
         if (!NoiseSuppressor.isAvailable()) {
             return;
         }
@@ -100,6 +109,10 @@
 
     //Test case 2.1: test AEC creation and release
     public void test2_1AecCreateAndRelease() throws Exception {
+        if (!hasMicrophone()) {
+            return;
+        }
+
         AudioRecord ar = getAudioRecord();
         assertNotNull("could not create AudioRecord", ar);
 
@@ -120,6 +133,10 @@
 
     //Test case 2.2: test AEC setEnabled() and getEnabled()
     public void test2_2AecSetEnabledGetEnabled() throws Exception {
+        if (!hasMicrophone()) {
+            return;
+        }
+
         if (!AcousticEchoCanceler.isAvailable()) {
             return;
         }
@@ -153,6 +170,10 @@
 
     //Test case 3.1: test AGC creation and release
     public void test3_1AgcCreateAndRelease() throws Exception {
+        if (!hasMicrophone()) {
+            return;
+        }
+
         AudioRecord ar = getAudioRecord();
         assertNotNull("could not create AudioRecord", ar);
 
@@ -173,6 +194,10 @@
 
     //Test case 3.2: test AGC setEnabled() and getEnabled()
     public void test3_2AgcSetEnabledGetEnabled() throws Exception {
+        if (!hasMicrophone()) {
+            return;
+        }
+
         if (!AutomaticGainControl.isAvailable()) {
             return;
         }
@@ -199,6 +224,10 @@
     //-----------------------------------------------------------------
     // private methods
     //----------------------------------
+    private boolean hasMicrophone() {
+        return getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_MICROPHONE);
+    }
 
     private AudioRecord getAudioRecord() {
         AudioRecord ar = null;
diff --git a/tests/tests/media/src/android/media/cts/BassBoostTest.java b/tests/tests/media/src/android/media/cts/BassBoostTest.java
index 9dcb4e9..c9bffd9 100644
--- a/tests/tests/media/src/android/media/cts/BassBoostTest.java
+++ b/tests/tests/media/src/android/media/cts/BassBoostTest.java
@@ -24,7 +24,7 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
-public class BassBoostTest extends AndroidTestCase {
+public class BassBoostTest extends PostProcTestBase {
 
     private String TAG = "BassBoostTest";
     private final static short TEST_STRENGTH = 500;
@@ -34,13 +34,6 @@
 
     private BassBoost mBassBoost = null;
     private BassBoost mBassBoost2 = null;
-    private int mSession = -1;
-    private boolean mHasControl = false;
-    private boolean mIsEnabled = false;
-    private int mChangedParameter = -1;
-    private boolean mInitialized = false;
-    private Looper mLooper = null;
-    private final Object mLock = new Object();
     private ListenerThread mEffectListenerLooper = null;
 
     //-----------------------------------------------------------------
@@ -53,10 +46,12 @@
 
     //Test case 0.0: test constructor and release
     public void test0_0ConstructorAndRelease() throws Exception {
+        if (!isBassBoostAvailable()) {
+            return;
+        }
         BassBoost eq = null;
         try {
             eq = new BassBoost(0, 0);
-            assertNotNull("could not create BassBoost", eq);
             try {
                 assertTrue("invalid effect ID", (eq.getId() != 0));
             } catch (IllegalStateException e) {
@@ -81,6 +76,9 @@
 
     //Test case 1.0: test strength
     public void test1_0Strength() throws Exception {
+        if (!isBassBoostAvailable()) {
+            return;
+        }
         getBassBoost(0);
         try {
             if (mBassBoost.getStrengthSupported()) {
@@ -110,6 +108,9 @@
 
     //Test case 1.1: test properties
     public void test1_1Properties() throws Exception {
+        if (!isBassBoostAvailable()) {
+            return;
+        }
         getBassBoost(0);
         try {
             BassBoost.Settings settings = mBassBoost.getProperties();
@@ -144,6 +145,9 @@
 
     //Test case 1.2: test setStrength() throws exception after release
     public void test1_2SetStrengthAfterRelease() throws Exception {
+        if (!isBassBoostAvailable()) {
+            return;
+        }
         getBassBoost(0);
         mBassBoost.release();
         try {
@@ -162,6 +166,9 @@
 
     //Test case 2.0: test setEnabled() and getEnabled() in valid state
     public void test2_0SetEnabledGetEnabled() throws Exception {
+        if (!isBassBoostAvailable()) {
+            return;
+        }
         getBassBoost(0);
         try {
             mBassBoost.setEnabled(true);
@@ -178,6 +185,9 @@
 
     //Test case 2.1: test setEnabled() throws exception after release
     public void test2_1SetEnabledAfterRelease() throws Exception {
+        if (!isBassBoostAvailable()) {
+            return;
+        }
         getBassBoost(0);
         mBassBoost.release();
         try {
@@ -196,6 +206,9 @@
 
     //Test case 3.0: test control status listener
     public void test3_0ControlStatusListener() throws Exception {
+        if (!isBassBoostAvailable()) {
+            return;
+        }
         synchronized(mLock) {
             mHasControl = true;
             mInitialized = false;
@@ -218,6 +231,9 @@
 
     //Test case 3.1: test enable status listener
     public void test3_1EnableStatusListener() throws Exception {
+        if (!isBassBoostAvailable()) {
+            return;
+        }
         synchronized(mLock) {
             mInitialized = false;
             createListenerLooper(false, true, false);
@@ -242,6 +258,9 @@
 
     //Test case 3.2: test parameter changed listener
     public void test3_2ParameterChangedListener() throws Exception {
+        if (!isBassBoostAvailable()) {
+            return;
+        }
         synchronized(mLock) {
             mInitialized = false;
             createListenerLooper(false, false, true);
@@ -413,5 +432,4 @@
             mBassBoost2 = null;
         }
     }
-
 }
\ No newline at end of file
diff --git a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
index 50f1575..7b21997 100644
--- a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
+++ b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
@@ -78,11 +78,11 @@
  */
 public class EncodeVirtualDisplayWithCompositionTest extends AndroidTestCase {
     private static final String TAG = "EncodeVirtualDisplayWithCompositionTest";
-    private static final boolean DBG = false;
+    private static final boolean DBG = true;
     private static final String MIME_TYPE = "video/avc";
 
-    private static final long DEFAULT_WAIT_TIMEOUT_MS = 5000;
-    private static final long DEFAULT_WAIT_TIMEOUT_US = 5000000;
+    private static final long DEFAULT_WAIT_TIMEOUT_MS = 3000;
+    private static final long DEFAULT_WAIT_TIMEOUT_US = 3000000;
 
     private static final int COLOR_RED =  makeColor(100, 0, 0);
     private static final int COLOR_BLUE =  makeColor(0, 100, 0);
@@ -229,7 +229,7 @@
             }
         });
         renderingThread.start();
-        renderingThread.join(20000);
+        renderingThread.join(60000);
         assertTrue(!renderingThread.isAlive());
         if (mTestException != null) {
             throw mTestException;
@@ -568,7 +568,7 @@
                 while (!mStopEncoding) {
                     int index = mEncoder.dequeueOutputBuffer(info, TIMEOUT_USEC_NORMAL);
                     if (DBG) {
-                        Log.i(TAG, "dequeOutputBuffer returned " + index);
+                        Log.i(TAG, "encoder dequeOutputBuffer returned " + index);
                     }
                     if (index >= 0) {
                         if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
diff --git a/tests/tests/media/src/android/media/cts/EnvReverbTest.java b/tests/tests/media/src/android/media/cts/EnvReverbTest.java
index edfef96..e2e9b6d 100644
--- a/tests/tests/media/src/android/media/cts/EnvReverbTest.java
+++ b/tests/tests/media/src/android/media/cts/EnvReverbTest.java
@@ -24,7 +24,7 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
-public class EnvReverbTest extends AndroidTestCase {
+public class EnvReverbTest extends PostProcTestBase {
 
     private String TAG = "EnvReverbTest";
     private final static int MILLIBEL_TOLERANCE = 100;            // +/-1dB
@@ -34,13 +34,6 @@
 
     private EnvironmentalReverb mReverb = null;
     private EnvironmentalReverb mReverb2 = null;
-    private int mSession = -1;
-    private boolean mHasControl = false;
-    private boolean mIsEnabled = false;
-    private int mChangedParameter = -1;
-    private boolean mInitialized = false;
-    private Looper mLooper = null;
-    private final Object mLock = new Object();
     private ListenerThread mEffectListenerLooper = null;
 
     //-----------------------------------------------------------------
@@ -53,10 +46,12 @@
 
     //Test case 0.0: test constructor and release
     public void test0_0ConstructorAndRelease() throws Exception {
+        if (!isEnvReverbAvailable()) {
+            return;
+        }
         EnvironmentalReverb envReverb = null;
          try {
             envReverb = new EnvironmentalReverb(0, 0);
-            assertNotNull("could not create EnvironmentalReverb", envReverb);
             try {
                 assertTrue("invalid effect ID", (envReverb.getId() != 0));
             } catch (IllegalStateException e) {
@@ -80,6 +75,9 @@
 
     //Test case 1.0: test room level and room HF level
     public void test1_0Room() throws Exception {
+        if (!isEnvReverbAvailable()) {
+            return;
+        }
         getReverb(0);
         try {
             short level = mReverb.getRoomLevel();
@@ -111,6 +109,9 @@
 
     //Test case 1.1: test decay time and ratio
     public void test1_1Decay() throws Exception {
+        if (!isEnvReverbAvailable()) {
+            return;
+        }
         getReverb(0);
         try {
             int time = mReverb.getDecayTime();
@@ -142,6 +143,9 @@
 
     //Test case 1.2: test reverb level and delay
     public void test1_2Reverb() throws Exception {
+        if (!isEnvReverbAvailable()) {
+            return;
+        }
         getReverb(0);
         try {
             short level = mReverb.getReverbLevel();
@@ -175,6 +179,9 @@
 
     //Test case 1.3: test early reflections level and delay
     public void test1_3Reflections() throws Exception {
+        if (!isEnvReverbAvailable()) {
+            return;
+        }
         getReverb(0);
         try {
 // FIXME:uncomment actual test when early reflections are implemented in the reverb
@@ -213,6 +220,9 @@
 
     //Test case 1.4: test diffusion and density
     public void test1_4DiffusionAndDensity() throws Exception {
+        if (!isEnvReverbAvailable()) {
+            return;
+        }
         getReverb(0);
         try {
             short ratio = mReverb.getDiffusion();
@@ -244,6 +254,9 @@
 
     //Test case 1.5: test properties
     public void test1_5Properties() throws Exception {
+        if (!isEnvReverbAvailable()) {
+            return;
+        }
         getReverb(0);
         try {
             EnvironmentalReverb.Settings settings = mReverb.getProperties();
@@ -273,6 +286,9 @@
 
     //Test case 2.0: test setEnabled() and getEnabled() in valid state
     public void test2_0SetEnabledGetEnabled() throws Exception {
+        if (!isEnvReverbAvailable()) {
+            return;
+        }
         getReverb(0);
         try {
             mReverb.setEnabled(true);
@@ -306,6 +322,9 @@
 
     //Test case 3.0: test control status listener
     public void test3_0ControlStatusListener() throws Exception {
+        if (!isEnvReverbAvailable()) {
+            return;
+        }
         synchronized(mLock) {
             mHasControl = true;
             mInitialized = false;
@@ -328,6 +347,9 @@
 
     //Test case 3.1: test enable status listener
     public void test3_1EnableStatusListener() throws Exception {
+        if (!isEnvReverbAvailable()) {
+            return;
+        }
          synchronized(mLock) {
             mInitialized = false;
             createListenerLooper(false, true, false);
@@ -352,6 +374,9 @@
 
     //Test case 3.2: test parameter changed listener
     public void test3_2ParameterChangedListener() throws Exception {
+        if (!isEnvReverbAvailable()) {
+            return;
+        }
         synchronized(mLock) {
             mInitialized = false;
             createListenerLooper(false, false, true);
@@ -523,5 +548,4 @@
             mReverb2 = null;
         }
     }
-
 }
\ No newline at end of file
diff --git a/tests/tests/media/src/android/media/cts/EqualizerTest.java b/tests/tests/media/src/android/media/cts/EqualizerTest.java
index 3bc0d8e..15f0c73 100644
--- a/tests/tests/media/src/android/media/cts/EqualizerTest.java
+++ b/tests/tests/media/src/android/media/cts/EqualizerTest.java
@@ -24,7 +24,7 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
-public class EqualizerTest extends AndroidTestCase {
+public class EqualizerTest extends PostProcTestBase {
 
     private String TAG = "EqualizerTest";
     private final static int MIN_NUMBER_OF_BANDS = 4;
@@ -37,13 +37,6 @@
 
     private Equalizer mEqualizer = null;
     private Equalizer mEqualizer2 = null;
-    private int mSession = -1;
-    private boolean mHasControl = false;
-    private boolean mIsEnabled = false;
-    private int mChangedParameter = -1;
-    private boolean mInitialized = false;
-    private Looper mLooper = null;
-    private final Object mLock = new Object();
     private ListenerThread mEffectListenerLooper = null;
 
     //-----------------------------------------------------------------
@@ -56,10 +49,12 @@
 
     //Test case 0.0: test constructor and release
     public void test0_0ConstructorAndRelease() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
         Equalizer eq = null;
         try {
             eq = new Equalizer(0, 0);
-            assertNotNull("could not create Equalizer", eq);
             try {
                 assertTrue("invalid effect ID", (eq.getId() != 0));
             } catch (IllegalStateException e) {
@@ -83,6 +78,9 @@
 
     //Test case 1.0: test setBandLevel() and getBandLevel()
     public void test1_0BandLevel() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
         getEqualizer(0);
         try {
             short numBands = mEqualizer.getNumberOfBands();
@@ -112,6 +110,9 @@
 
     //Test case 1.1: test band frequency
     public void test1_1BandFrequency() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
         getEqualizer(0);
         try {
             short band = mEqualizer.getBand(TEST_FREQUENCY_MILLIHERTZ);
@@ -137,6 +138,9 @@
 
     //Test case 1.2: test presets
     public void test1_2Presets() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
         getEqualizer(0);
         try {
             short numPresets = mEqualizer.getNumberOfPresets();
@@ -162,6 +166,9 @@
 
     //Test case 1.3: test properties
     public void test1_3Properties() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
         getEqualizer(0);
         try {
             Equalizer.Settings settings = mEqualizer.getProperties();
@@ -193,7 +200,9 @@
 
     //Test case 1.4: test setBandLevel() throws exception after release
     public void test1_4SetBandLevelAfterRelease() throws Exception {
-
+        if (!hasAudioOutput()) {
+            return;
+        }
         getEqualizer(0);
         mEqualizer.release();
         try {
@@ -211,6 +220,9 @@
 
     //Test case 2.0: test setEnabled() and getEnabled() in valid state
     public void test2_0SetEnabledGetEnabled() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
         getEqualizer(0);
         try {
             mEqualizer.setEnabled(true);
@@ -227,7 +239,9 @@
 
     //Test case 2.1: test setEnabled() throws exception after release
     public void test2_1SetEnabledAfterRelease() throws Exception {
-
+        if (!hasAudioOutput()) {
+            return;
+        }
         getEqualizer(0);
         mEqualizer.release();
         try {
@@ -245,6 +259,9 @@
 
     //Test case 3.0: test control status listener
     public void test3_0ControlStatusListener() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
         synchronized(mLock) {
             mHasControl = true;
             mInitialized = false;
@@ -267,6 +284,9 @@
 
     //Test case 3.1: test enable status listener
     public void test3_1EnableStatusListener() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
         synchronized(mLock) {
             mInitialized = false;
             createListenerLooper(false, true, false);
@@ -291,6 +311,9 @@
 
     //Test case 3.2: test parameter changed listener
     public void test3_2ParameterChangedListener() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
         synchronized(mLock) {
             mInitialized = false;
             createListenerLooper(false, false, true);
@@ -460,5 +483,4 @@
             mEqualizer2 = null;
         }
     }
-
 }
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
index 08e6212..67c0591 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
@@ -56,13 +56,14 @@
             Log.i(TAG, "AvcBaseline12 not supported");
             return;  // TODO: Can we make this mandatory?
         }
+
         playVideoWithRetries("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e"
                 + "&itag=160&source=youtube&user=android-device-test"
                 + "&sparams=ip,ipbits,expire,id,itag,source,user"
-                + "&ip=0.0.0.0&ipbits=0&expire=999999999999999999"
-                + "&signature=341692D20FACCAE25B90EA2C131EA6ADCD8E2384."
-                + "9EB08C174BE401AAD20FB85EE4DBA51A2882BB60"
-                + "&key=test_key1", 256, 144, PLAY_TIME_MS);
+                + "&ip=0.0.0.0&ipbits=0&expire=19000000000"
+                + "&signature=9EDCA0B395B8A949C511FD5E59B9F805CFF797FD."
+                + "702DE9BA7AF96785FD6930AD2DD693A0486C880E"
+                + "&key=ik0", 256, 144, PLAY_TIME_MS);
     }
 
     public void testAvcBaseline30() throws Exception {
@@ -77,10 +78,10 @@
         playVideoWithRetries("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e"
                 + "&itag=18&source=youtube&user=android-device-test"
                 + "&sparams=ip,ipbits,expire,id,itag,source,user"
-                + "&ip=0.0.0.0&ipbits=0&expire=999999999999999999"
-                + "&signature=8701A45F6422229D46ABB25A22E2C00C94024606."
-                + "08BCDF16C3F744C49D4C8A8AD1C38B3DC1810918"
-                + "&key=test_key1", 640, 360, PLAY_TIME_MS);
+                + "&ip=0.0.0.0&ipbits=0&expire=19000000000"
+                + "&signature=7DCDE3A6594D0B91A27676A3CDC3A87B149F82EA."
+                + "7A83031734CB1EDCE06766B6228842F954927960"
+                + "&key=ik0", 640, 360, PLAY_TIME_MS);
     }
 
     public void testAvcHigh31() throws Exception {
@@ -95,11 +96,10 @@
         playVideoWithRetries("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e"
                 + "&itag=22&source=youtube&user=android-device-test"
                 + "&sparams=ip,ipbits,expire,id,itag,source,user"
-                + "&ip=0.0.0.0&ipbits=0&expire=999999999999999999"
-                + "&signature=42969CA8F7FFAE432B7135BC811F96F7C4172C3F."
-                + "1A8A92EA714C1B7C98A05DDF2DE90854CDD7638B"
-                + "&key=test_key1", 1280, 720, PLAY_TIME_MS);
-
+                + "&ip=0.0.0.0&ipbits=0&expire=19000000000"
+                + "&signature=179525311196616BD8E1381759B0E5F81A9E91B5."
+                + "C4A50E44059FEBCC6BBC78E3B3A4E0E0065777"
+                + "&key=ik0", 1280, 720, PLAY_TIME_MS);
     }
 
     public void testAvcHigh40() throws Exception {
@@ -118,10 +118,10 @@
         playVideoWithRetries("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e"
                 + "&itag=137&source=youtube&user=android-device-test"
                 + "&sparams=ip,ipbits,expire,id,itag,source,user"
-                + "&ip=0.0.0.0&ipbits=0&expire=999999999999999999"
-                + "&signature=2C836E04C4DDC98649CD44C8B91813D98342D1D1."
-                + "870A848D54CA08C197E5FDC34ED45E6ED7DB5CDA"
-                + "&key=test_key1", 1920, 1080, PLAY_TIME_MS);
+                + "&ip=0.0.0.0&ipbits=0&expire=19000000000"
+                + "&signature=B0976085596DD42DEA3F08307F76587241CB132B."
+                + "043B719C039E8B92F45391ADC0BE3665E2332930"
+                + "&key=ik0", 1920, 1080, PLAY_TIME_MS);
     }
 
     public void testHevcMain1() throws Exception {
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java b/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
index d8a20e9..865780e 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
@@ -16,24 +16,38 @@
 
 package android.media.cts;
 
-
+import android.content.pm.PackageManager;
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
 import android.media.MediaCodecInfo.CodecProfileLevel;
 import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecInfo.AudioCapabilities;
+import android.media.MediaCodecInfo.VideoCapabilities;
+import android.media.MediaCodecInfo.EncoderCapabilities;
 import android.media.MediaCodecList;
+import android.media.MediaFormat;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
 import java.io.File;
 import java.io.IOException;
-import java.util.List;
 import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 public class MediaCodecListTest extends AndroidTestCase {
 
     private static final String TAG = "MediaCodecListTest";
     private static final String MEDIA_CODEC_XML_FILE = "/etc/media_codecs.xml";
+    private final MediaCodecList mRegularCodecs =
+            new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+    private final MediaCodecList mAllCodecs =
+            new MediaCodecList(MediaCodecList.ALL_CODECS);
+    private final MediaCodecInfo[] mRegularInfos =
+            mRegularCodecs.getCodecInfos();
+    private final MediaCodecInfo[] mAllInfos =
+            mAllCodecs.getCodecInfos();
 
     class CodecType {
         CodecType(String type, boolean isEncoder) {
@@ -55,55 +69,120 @@
         assertTrue("/etc/media_codecs.xml does not exist", file.exists());
     }
 
-    // Each component advertised by MediaCodecList should at least be
-    // instantiate-able.
-    public void testComponentInstantiation() throws IOException {
-        Log.d(TAG, "testComponentInstantiation");
+    private MediaCodecInfo[] getLegacyInfos() {
+        Log.d(TAG, "getLegacyInfos");
 
         int codecCount = MediaCodecList.getCodecCount();
-        for (int i = 0; i < codecCount; ++i) {
-            MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
+        MediaCodecInfo[] res = new MediaCodecInfo[codecCount];
 
-            Log.d(TAG, (i + 1) + ": " + info.getName());
+        for (int i = 0; i < codecCount; ++i) {
+            res[i] = MediaCodecList.getCodecInfoAt(i);
+        }
+        return res;
+    }
+
+    public void assertEqualsOrSuperset(Set big, Set tiny, boolean superset) {
+        if (!superset) {
+            assertEquals(big, tiny);
+        } else {
+            assertTrue(big.containsAll(tiny));
+        }
+    }
+
+    private static <T> Set<T> asSet(T[] array) {
+        Set<T> s = new HashSet<T>();
+        for (T el : array) {
+            s.add(el);
+        }
+        return s;
+    }
+
+    private static Set<Integer> asSet(int[] array) {
+        Set<Integer> s = new HashSet<Integer>();
+        for (int el : array) {
+            s.add(el);
+        }
+        return s;
+    }
+
+    public void assertEqualsOrSuperset(
+            CodecCapabilities big, CodecCapabilities tiny, boolean superset) {
+        // ordering of enumerations may differ
+        assertEqualsOrSuperset(asSet(big.colorFormats), asSet(tiny.colorFormats), superset);
+        assertEqualsOrSuperset(asSet(big.profileLevels), asSet(tiny.profileLevels), superset);
+        AudioCapabilities bigAudCaps = big.getAudioCapabilities();
+        VideoCapabilities bigVidCaps = big.getVideoCapabilities();
+        EncoderCapabilities bigEncCaps = big.getEncoderCapabilities();
+        AudioCapabilities tinyAudCaps = tiny.getAudioCapabilities();
+        VideoCapabilities tinyVidCaps = tiny.getVideoCapabilities();
+        EncoderCapabilities tinyEncCaps = tiny.getEncoderCapabilities();
+        assertEquals(bigAudCaps != null, tinyAudCaps != null);
+        assertEquals(bigAudCaps != null, tinyAudCaps != null);
+        assertEquals(bigAudCaps != null, tinyAudCaps != null);
+    }
+
+    public void assertEqualsOrSuperset(
+            MediaCodecInfo big, MediaCodecInfo tiny, boolean superset) {
+        assertEquals(big.getName(), tiny.getName());
+        assertEquals(big.isEncoder(), tiny.isEncoder());
+        assertEqualsOrSuperset(
+                asSet(big.getSupportedTypes()), asSet(tiny.getSupportedTypes()), superset);
+        for (String type : big.getSupportedTypes()) {
+            assertEqualsOrSuperset(
+                    big.getCapabilitiesForType(type),
+                    tiny.getCapabilitiesForType(type),
+                    superset);
+        }
+    }
+
+    public void assertSuperset(MediaCodecInfo big, MediaCodecInfo tiny) {
+        assertEqualsOrSuperset(big, tiny, true /* superset */);
+    }
+
+    public void assertEquals(MediaCodecInfo big, MediaCodecInfo tiny) {
+        assertEqualsOrSuperset(big, tiny, false /* superset */);
+    }
+
+    // Each component advertised by MediaCodecList should at least be
+    // instantiable.
+    private void testComponentInstantiation(MediaCodecInfo[] infos) throws IOException {
+        for (MediaCodecInfo info : infos) {
+            Log.d(TAG, "codec: " + info.getName());
             Log.d(TAG, "  isEncoder = " + info.isEncoder());
 
-            if (!info.getName().startsWith("OMX.")) {
-                // Unfortunately for legacy reasons, "AACEncoder", a
-                // non OMX component had to be in this list for the video
-                // editor code to work... but it cannot actually be instantiated
-                // using MediaCodec.
-                Log.d(TAG, "  skipping...");
-                continue;
-            }
-
             MediaCodec codec = MediaCodec.createByCodecName(info.getName());
 
+            assertEquals(codec.getName(), info.getName());
+
+            assertEquals(codec.getCodecInfo(), info);
+
             codec.release();
             codec = null;
         }
     }
 
+    public void testRegularComponentInstantiation() throws IOException {
+        Log.d(TAG, "testRegularComponentInstantiation");
+        testComponentInstantiation(mRegularInfos);
+    }
+
+    public void testAllComponentInstantiation() throws IOException {
+        Log.d(TAG, "testAllComponentInstantiation");
+        testComponentInstantiation(mAllInfos);
+    }
+
+    public void testLegacyComponentInstantiation() throws IOException {
+        Log.d(TAG, "testLegacyComponentInstantiation");
+        testComponentInstantiation(getLegacyInfos());
+    }
+
     // For each type advertised by any of the components we should be able
     // to get capabilities.
-    public void testGetCapabilities() {
-        Log.d(TAG, "testGetCapabilities");
-
-        int codecCount = MediaCodecList.getCodecCount();
-        for (int i = 0; i < codecCount; ++i) {
-            MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
-
-            Log.d(TAG, (i + 1) + ": " + info.getName());
+    private void testGetCapabilities(MediaCodecInfo[] infos) {
+        for (MediaCodecInfo info : infos) {
+            Log.d(TAG, "codec: " + info.getName());
             Log.d(TAG, "  isEncoder = " + info.isEncoder());
 
-            if (!info.getName().startsWith("OMX.")) {
-                // Unfortunately for legacy reasons, "AACEncoder", a
-                // non OMX component had to be in this list for the video
-                // editor code to work... but it cannot actually be instantiated
-                // using MediaCodec.
-                Log.d(TAG, "  skipping...");
-                continue;
-            }
-
             String[] types = info.getSupportedTypes();
             for (int j = 0; j < types.length; ++j) {
                 Log.d(TAG, "calling getCapabilitiesForType " + types[j]);
@@ -112,14 +191,71 @@
         }
     }
 
+    public void testGetRegularCapabilities() {
+        Log.d(TAG, "testGetRegularCapabilities");
+        testGetCapabilities(mRegularInfos);
+    }
+
+    public void testGetAllCapabilities() {
+        Log.d(TAG, "testGetAllCapabilities");
+        testGetCapabilities(mAllInfos);
+    }
+
+    public void testGetLegacyCapabilities() {
+        Log.d(TAG, "testGetLegacyCapabilities");
+        testGetCapabilities(getLegacyInfos());
+    }
+
+    public void testLegacyMediaCodecListIsSameAsRegular() {
+        // regular codecs should be equivalent to legacy codecs, including
+        // codec ordering
+        MediaCodecInfo[] legacyInfos = getLegacyInfos();
+        assertEquals(legacyInfos.length, mRegularInfos.length);
+        for (int i = 0; i < legacyInfos.length; ++i) {
+            assertEquals(legacyInfos[i], mRegularInfos[i]);
+        }
+    }
+
+    public void testRegularMediaCodecListIsASubsetOfAll() {
+        Log.d(TAG, "testRegularMediaCodecListIsASubsetOfAll");
+        // regular codecs should be a subsequence of all codecs, including
+        // codec ordering
+        int ix = 0;
+        for (MediaCodecInfo info : mAllInfos) {
+            if (ix == mRegularInfos.length) {
+                break;
+            }
+            if (!mRegularInfos[ix].getName().equals(info.getName())) {
+                Log.d(TAG, "skipping non-regular codec " + info.getName());
+                continue;
+            }
+            Log.d(TAG, "checking codec " + info.getName());
+            assertSuperset(info, mRegularInfos[ix]);
+            ++ix;
+        }
+        assertEquals(
+                "some regular codecs are not listed in all codecs", ix, mRegularInfos.length);
+    }
+
     public void testRequiredMediaCodecList() {
         List<CodecType> requiredList = getRequiredCodecTypes();
         List<CodecType> supportedList = getSupportedCodecTypes();
         assertTrue(areRequiredCodecTypesSupported(requiredList, supportedList));
     }
 
+    private boolean hasCamera() {
+        PackageManager pm = getContext().getPackageManager();
+        return pm.hasSystemFeature(pm.FEATURE_CAMERA_FRONT) ||
+                pm.hasSystemFeature(pm.FEATURE_CAMERA);
+    }
+
     // H263 baseline profile must be supported
     public void testIsH263BaselineProfileSupported() {
+        if (!hasCamera()) {
+            Log.d(TAG, "not required without camera");
+            return;
+        }
+
         int profile = CodecProfileLevel.H263ProfileBaseline;
         assertTrue(checkProfileSupported("video/3gpp", false, profile));
         assertTrue(checkProfileSupported("video/3gpp", true, profile));
@@ -140,6 +276,11 @@
 
     // MPEG4 simple profile must be supported
     public void testIsM4VSimpleProfileSupported() {
+        if (!hasCamera()) {
+            Log.d(TAG, "not required without camera");
+            return;
+        }
+
         int profile = CodecProfileLevel.MPEG4ProfileSimple;
         assertTrue(checkProfileSupported("video/mp4v-es", false, profile));
 
@@ -151,26 +292,24 @@
      * Find whether the given codec is supported
      */
     private boolean checkProfileSupported(
-        String codecName, boolean isEncoder, int profile) {
+            String mime, boolean isEncoder, int profile) {
+        return profileIsListed(mime, isEncoder, profile) &&
+                codecCanBeFound(mime, isEncoder);
+    }
 
-        boolean isSupported = false;
+    private boolean profileIsListed(
+        String mime, boolean isEncoder, int profile) {
 
-        int codecCount = MediaCodecList.getCodecCount();
-        for (int i = 0; i < codecCount; ++i) {
-
-            MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
-            String[] types = info.getSupportedTypes();
-
+        for (MediaCodecInfo info : mRegularInfos) {
             if (isEncoder != info.isEncoder()) {
                 continue;
             }
 
-            for (int j = 0; j < types.length; ++j) {
-                if (types[j].compareTo(codecName) == 0) {
-                    CodecCapabilities cap = info.getCapabilitiesForType(types[j]);
-                    CodecProfileLevel[] profileLevels = cap.profileLevels;
-                    for (int k = 0; k < profileLevels.length; ++k) {
-                        if (profileLevels[k].profile == profile) {
+            for (String type : info.getSupportedTypes()) {
+                if (type.equalsIgnoreCase(mime)) {
+                    CodecCapabilities cap = info.getCapabilitiesForType(type);
+                    for (CodecProfileLevel pl : cap.profileLevels) {
+                        if (pl.profile == profile) {
                             return true;
                         }
                     }
@@ -180,6 +319,16 @@
         return false;
     }
 
+    // Find whether the given codec can be found using MediaCodecList.find methods.
+    private boolean codecCanBeFound(String mime, boolean isEncoder) {
+        // implicit assumption that QVGA video is always valid.
+        MediaFormat format = MediaFormat.createVideoFormat(mime, 176, 144);
+        String codecName = isEncoder
+                ? mRegularCodecs.findEncoderForFormat(format)
+                : mRegularCodecs.findDecoderForFormat(format);
+        return codecName != null;
+    }
+
     /*
      * Find whether all required media codec types are supported
      */
@@ -206,11 +355,8 @@
      * Find all the media codec types are supported.
      */
     private List<CodecType> getSupportedCodecTypes() {
-        int codecCount = MediaCodecList.getCodecCount();
-        assertTrue("Unexpected media codec count", codecCount > 0);
-        List<CodecType> supportedList = new ArrayList<CodecType>(codecCount);
-        for (int i = 0; i < codecCount; ++i) {
-            MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
+        List<CodecType> supportedList = new ArrayList<CodecType>();
+        for (MediaCodecInfo info : mRegularInfos) {
             String[] types = info.getSupportedTypes();
             assertTrue("Unexpected number of supported types", types.length > 0);
             boolean isEncoder = info.isEncoder();
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecTest.java b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
index 6726728..f72e3a0 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
@@ -402,8 +402,7 @@
             inputSurface.makeCurrent();
             encoder.start();
 
-            int totalBuffers = encoder.getInputBuffers().length +
-                    encoder.getOutputBuffers().length;
+            int totalBuffers = encoder.getOutputBuffers().length;
             if (VERBOSE) Log.d(TAG, "Total buffers: " + totalBuffers);
 
             // Submit several frames quickly, without draining the encoder output, to try to
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
index 2815d81..799fd59 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
@@ -85,6 +85,37 @@
         }
     }
 
+    public void testFlacHeapOverflow() throws Exception {
+        testIfMediaServerDied(R.raw.heap_oob_flac);
+    }
+
+    private void testIfMediaServerDied(int res) throws Exception {
+        mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
+            @Override
+            public boolean onError(MediaPlayer mp, int what, int extra) {
+                assertTrue(mp == mMediaPlayer);
+                assertTrue("mediaserver process died", what != MediaPlayer.MEDIA_ERROR_SERVER_DIED);
+                return false;
+            }
+        });
+
+        mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
+            @Override
+            public void onCompletion(MediaPlayer mp) {
+                assertTrue(mp == mMediaPlayer);
+                mOnCompletionCalled.signal();
+            }
+        });
+
+        AssetFileDescriptor afd = mResources.openRawResourceFd(res);
+        mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
+        afd.close();
+        mMediaPlayer.prepare();
+        mMediaPlayer.start();
+        mOnCompletionCalled.waitForSignal();
+        mMediaPlayer.release();
+    }
+
     // Bug 13652927
     public void testVorbisCrash() throws Exception {
         MediaPlayer mp = mMediaPlayer;
@@ -239,6 +270,46 @@
         }
     }
 
+    public void testPlayMidi() throws Exception {
+        final int resid = R.raw.midi8sec;
+        final int midiDuration = 8000;
+        final int tolerance = 70;
+        final int seekDuration = 1000;
+
+        MediaPlayer mp = MediaPlayer.create(mContext, resid);
+        try {
+            mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
+            mp.setWakeMode(mContext, PowerManager.PARTIAL_WAKE_LOCK);
+
+            mp.start();
+
+            assertFalse(mp.isLooping());
+            mp.setLooping(true);
+            assertTrue(mp.isLooping());
+
+            assertEquals(midiDuration, mp.getDuration(), tolerance);
+            int pos = mp.getCurrentPosition();
+            assertTrue(pos >= 0);
+            assertTrue(pos < midiDuration - seekDuration);
+
+            mp.seekTo(pos + seekDuration);
+            assertEquals(pos + seekDuration, mp.getCurrentPosition(), tolerance);
+
+            // test stop and restart
+            mp.stop();
+            mp.reset();
+            AssetFileDescriptor afd = mResources.openRawResourceFd(resid);
+            mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
+            afd.close();
+            mp.prepare();
+            mp.start();
+
+            Thread.sleep(SLEEP_TIME);
+        } finally {
+            mp.release();
+        }
+    }
+
     static class OutputListener {
         int mSession;
         AudioEffect mVc;
@@ -593,14 +664,16 @@
         }
         byte [] vizdata = new byte[size];
         Visualizer vis = new Visualizer(session);
-        assertTrue(vis.setCaptureSize(vizdata.length) == Visualizer.SUCCESS);
-        assertTrue(vis.setEnabled(true) == Visualizer.SUCCESS);
         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 {
+            assertEquals("setCaptureSize failed",
+                    Visualizer.SUCCESS, vis.setCaptureSize(vizdata.length));
+            assertEquals("setEnabled failed", Visualizer.SUCCESS, vis.setEnabled(true));
+
             mp1.setNextMediaPlayer(mp2);
             mp1.start();
             assertTrue(mp1.isPlaying());
diff --git a/tests/tests/media/src/android/media/cts/PostProcTestBase.java b/tests/tests/media/src/android/media/cts/PostProcTestBase.java
new file mode 100644
index 0000000..b034763
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/PostProcTestBase.java
@@ -0,0 +1,65 @@
+/*
+ * 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.media.cts;
+
+import android.content.pm.PackageManager;
+import android.media.audiofx.AudioEffect;
+import android.os.Looper;
+import android.test.AndroidTestCase;
+
+public class PostProcTestBase extends AndroidTestCase {
+    protected int mSession = -1;
+    protected boolean mHasControl = false;
+    protected boolean mIsEnabled = false;
+    protected boolean mInitialized = false;
+    protected Looper mLooper = null;
+    protected final Object mLock = new Object();
+    protected int mChangedParameter = -1;
+
+    protected boolean hasAudioOutput() {
+        return getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_AUDIO_OUTPUT);
+    }
+
+    protected boolean isBassBoostAvailable() {
+        if (!hasAudioOutput()) {
+            return false;
+        }
+        return AudioEffect.isEffectTypeAvailable(AudioEffect.EFFECT_TYPE_BASS_BOOST);
+    }
+
+    protected boolean isVirtualizerAvailable() {
+        if (!hasAudioOutput()) {
+            return false;
+        }
+        return AudioEffect.isEffectTypeAvailable(AudioEffect.EFFECT_TYPE_VIRTUALIZER);
+    }
+
+    protected boolean isPresetReverbAvailable() {
+        if (!hasAudioOutput()) {
+            return false;
+        }
+        return AudioEffect.isEffectTypeAvailable(AudioEffect.EFFECT_TYPE_PRESET_REVERB);
+    }
+
+    protected boolean isEnvReverbAvailable() {
+        if (!hasAudioOutput()) {
+            return false;
+        }
+        return AudioEffect.isEffectTypeAvailable(AudioEffect.EFFECT_TYPE_ENV_REVERB);
+    }
+}
diff --git a/tests/tests/media/src/android/media/cts/PresetReverbTest.java b/tests/tests/media/src/android/media/cts/PresetReverbTest.java
index d69256c..ba6d08c 100644
--- a/tests/tests/media/src/android/media/cts/PresetReverbTest.java
+++ b/tests/tests/media/src/android/media/cts/PresetReverbTest.java
@@ -24,7 +24,7 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
-public class PresetReverbTest extends AndroidTestCase {
+public class PresetReverbTest extends PostProcTestBase {
 
     private String TAG = "PresetReverbTest";
     private final static short FIRST_PRESET = PresetReverb.PRESET_NONE;
@@ -33,13 +33,6 @@
 
     private PresetReverb mReverb = null;
     private PresetReverb mReverb2 = null;
-    private int mSession = -1;
-    private boolean mHasControl = false;
-    private boolean mIsEnabled = false;
-    private int mChangedParameter = -1;
-    private boolean mInitialized = false;
-    private Looper mLooper = null;
-    private final Object mLock = new Object();
     private ListenerThread mEffectListenerLooper = null;
 
     //-----------------------------------------------------------------
@@ -52,10 +45,12 @@
 
     //Test case 0.0: test constructor and release
     public void test0_0ConstructorAndRelease() throws Exception {
+        if (!isPresetReverbAvailable()) {
+            return;
+        }
         PresetReverb reverb = null;
         try {
             reverb = new PresetReverb(0, 0);
-            assertNotNull("could not create PresetReverb", reverb);
             try {
                 assertTrue("invalid effect ID", (reverb.getId() != 0));
             } catch (IllegalStateException e) {
@@ -78,6 +73,9 @@
 
     //Test case 1.0: test presets
     public void test1_0Presets() throws Exception {
+        if (!isPresetReverbAvailable()) {
+            return;
+        }
         getReverb(0);
         try {
             for (short preset = FIRST_PRESET;
@@ -99,6 +97,9 @@
 
     //Test case 1.1: test properties
     public void test1_1Properties() throws Exception {
+        if (!isPresetReverbAvailable()) {
+            return;
+        }
         getReverb(0);
         try {
             PresetReverb.Settings settings = mReverb.getProperties();
@@ -127,6 +128,9 @@
 
     //Test case 2.0: test setEnabled() and getEnabled() in valid state
     public void test2_0SetEnabledGetEnabled() throws Exception {
+        if (!isPresetReverbAvailable()) {
+            return;
+        }
         getReverb(0);
         try {
             mReverb.setEnabled(true);
@@ -142,6 +146,9 @@
 
     //Test case 2.1: test setEnabled() throws exception after release
     public void test2_1SetEnabledAfterRelease() throws Exception {
+        if (!isPresetReverbAvailable()) {
+            return;
+        }
         getReverb(0);
         mReverb.release();
         try {
@@ -159,6 +166,9 @@
 
     //Test case 3.0: test control status listener
     public void test3_0ControlStatusListener() throws Exception {
+        if (!isPresetReverbAvailable()) {
+            return;
+        }
          synchronized(mLock) {
             mHasControl = true;
             mInitialized = false;
@@ -181,6 +191,9 @@
 
     //Test case 3.1: test enable status listener
     public void test3_1EnableStatusListener() throws Exception {
+        if (!isPresetReverbAvailable()) {
+            return;
+        }
          synchronized(mLock) {
             mInitialized = false;
             createListenerLooper(false, true, false);
@@ -205,6 +218,9 @@
 
     //Test case 3.2: test parameter changed listener
     public void test3_2ParameterChangedListener() throws Exception {
+        if (!isPresetReverbAvailable()) {
+            return;
+        }
         synchronized(mLock) {
             mInitialized = false;
             createListenerLooper(false, false, true);
@@ -377,5 +393,4 @@
             mReverb2 = null;
         }
     }
-
 }
\ No newline at end of file
diff --git a/tests/tests/media/src/android/media/cts/SoundPoolMidiTest.java b/tests/tests/media/src/android/media/cts/SoundPoolMidiTest.java
new file mode 100644
index 0000000..a8c640e
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/SoundPoolMidiTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.media.cts;
+
+import com.android.cts.media.R;
+
+public class SoundPoolMidiTest extends SoundPoolTest {
+
+    @Override
+    protected int getSoundA() {
+        return R.raw.midi_a;
+    }
+
+    @Override
+    protected int getSoundCs() {
+        return R.raw.midi_cs;
+    }
+
+    @Override
+    protected int getSoundE() {
+        return R.raw.midi_e;
+    }
+
+    @Override
+    protected int getSoundB() {
+        return R.raw.midi_b;
+    }
+
+    @Override
+    protected int getSoundGs() {
+        return R.raw.midi_gs;
+    }
+
+    @Override
+    protected String getFileName() {
+        return "midi_a.mid";
+    }
+}
diff --git a/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java b/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
index 2b93064..419f3e0 100644
--- a/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
@@ -65,51 +65,51 @@
         playVideoTest("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e"
                 + "&itag=13&source=youtube&ip=0.0.0.0&ipbits=0&expire=19000000000"
                 + "&sparams=ip,ipbits,expire,id,itag,source"
-                + "&signature=6F5AEC448AAF88466D7A10EBB76020745405D33F."
-                + "5050D35AE997E1535FE828B0DE99EF31A699D9D0"
-                + "&key=test_key1&user=android-device-test", 176, 144);
+                + "&signature=5729247E22691EBB3E804DDD523EC42DC17DD8CE"
+                + ".443B81C1E8E6D64E4E1555F568BA46C206507D78"
+                + "&key=ik0&user=android-device-test", 176, 144);
     }
     public void testHTTP_H263_AMR_Video2() throws Exception {
         playVideoTest("http://redirector.c.youtube.com/videoplayback?id=c80658495af60617"
                 + "&itag=13&source=youtube&ip=0.0.0.0&ipbits=0&expire=19000000000"
                 + "&sparams=ip,ipbits,expire,id,itag,source"
-                + "&signature=71749754E28115FD1C233E3BE96CDDC3F430CB74."
-                + "49D1506DE694CC8FCEE63CB4F3AD41EB76C198CE"
-                + "&key=test_key1&user=android-device-test", 176, 144);
+                + "&signature=508D82AB36939345BF6B8D0623CB6CABDD9C64C3"
+                + ".9B3336A96846DF38E5343C46AA57F6CF2956E427"
+                + "&key=ik0&user=android-device-test", 176, 144);
     }
 
     public void testHTTP_MPEG4SP_AAC_Video1() throws Exception {
         playVideoTest("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e"
                 + "&itag=17&source=youtube&ip=0.0.0.0&ipbits=0&expire=19000000000"
                 + "&sparams=ip,ipbits,expire,id,itag,source"
-                + "&signature=197A9742C1EFCA95725F2F26DFFD512FC48C149F."
-                + "A59B42FD490F6B591B292F3B2659A9723B980351"
-                + "&key=test_key1&user=android-device-test", 176, 144);
+                + "&signature=837198AAADF6F36BA6B2D324F690A7C5B7AFE3FF"
+                + ".7138CE5E36D718220726C1FC305497FF2D082249"
+                + "&key=ik0&user=android-device-test", 176, 144);
     }
     public void testHTTP_MPEG4SP_AAC_Video2() throws Exception {
         playVideoTest("http://redirector.c.youtube.com/videoplayback?id=c80658495af60617"
                 + "&itag=17&source=youtube&ip=0.0.0.0&ipbits=0&expire=19000000000"
                 + "&sparams=ip,ipbits,expire,id,itag,source"
-                + "&signature=0F84740A7E06F884127E78A6D7DE6DEA8F4B8BFD."
-                + "248DF1E90B8137C30769C79BF23147F6BB3DFCDF"
-                + "&key=test_key1&user=android-device-test", 176, 144);
+                + "&signature=70E979A621001201BC18622BDBF914FA870BDA40"
+                + ".6E78890B80F4A33A18835F775B1FF64F0A4D0003"
+                + "&key=ik0&user=android-device-test", 176, 144);
     }
 
     public void testHTTP_H264Base_AAC_Video1() throws Exception {
         playVideoTest("http://redirector.c.youtube.com/videoplayback?id=271de9756065677e"
                 + "&itag=18&source=youtube&ip=0.0.0.0&ipbits=0&expire=19000000000"
                 + "&sparams=ip,ipbits,expire,id,itag,source"
-                + "&signature=3CFCAFB87EB9FC943FACDC54FEC8C725A801642C."
-                + "7D77ACBC4CAF40349BF093E302B635757E45F345"
-                + "&key=test_key1&user=android-device-test", 640, 360);
+                + "&signature=667AEEF54639926662CE62361400B8F8C1753B3F"
+                + ".15F46C382C68A9F121BA17BF1F56BEDEB4B06091"
+                + "&key=ik0&user=android-device-test", 640, 360);
     }
     public void testHTTP_H264Base_AAC_Video2() throws Exception {
         playVideoTest("http://redirector.c.youtube.com/videoplayback?id=c80658495af60617"
                 + "&itag=18&source=youtube&ip=0.0.0.0&ipbits=0&expire=19000000000"
                 + "&sparams=ip,ipbits,expire,id,itag,source"
-                + "&signature=A11D8BA0AA67A27F1409BE0C0B96B756625DB88B."
-                + "9BF4C93A130583ADBDF2B953AD5A8A58F518B012"
-                + "&key=test_key1&user=android-device-test", 640, 360);
+                + "&signature=46A04ED550CA83B79B60060BA80C79FDA5853D26"
+                + ".49582D382B4A9AFAA163DED38D2AE531D85603C0"
+                + "&key=ik0&user=android-device-test", 640, 360);
     }
 
     // Streaming HLS video from YouTube
diff --git a/tests/tests/media/src/android/media/cts/VirtualizerTest.java b/tests/tests/media/src/android/media/cts/VirtualizerTest.java
index 3d18c47..51adf1d 100644
--- a/tests/tests/media/src/android/media/cts/VirtualizerTest.java
+++ b/tests/tests/media/src/android/media/cts/VirtualizerTest.java
@@ -24,7 +24,7 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
-public class VirtualizerTest extends AndroidTestCase {
+public class VirtualizerTest extends PostProcTestBase {
 
     private String TAG = "VirtualizerTest";
     private final static short TEST_STRENGTH = 500;
@@ -34,13 +34,6 @@
 
     private Virtualizer mVirtualizer = null;
     private Virtualizer mVirtualizer2 = null;
-    private int mSession = -1;
-    private boolean mHasControl = false;
-    private boolean mIsEnabled = false;
-    private int mChangedParameter = -1;
-    private boolean mInitialized = false;
-    private Looper mLooper = null;
-    private final Object mLock = new Object();
     private ListenerThread mEffectListenerLooper = null;
 
     //-----------------------------------------------------------------
@@ -53,10 +46,13 @@
 
     //Test case 0.0: test constructor and release
     public void test0_0ConstructorAndRelease() throws Exception {
+        if (!isVirtualizerAvailable()) {
+            return;
+        }
+
         Virtualizer eq = null;
         try {
             eq = new Virtualizer(0, 0);
-            assertNotNull(" could not create Virtualizer", eq);
             try {
                 assertTrue(" invalid effect ID", (eq.getId() != 0));
             } catch (IllegalStateException e) {
@@ -80,6 +76,10 @@
 
     //Test case 1.0: test strength
     public void test1_0Strength() throws Exception {
+        if (!isVirtualizerAvailable()) {
+            return;
+        }
+
         getVirtualizer(0);
         try {
             if (mVirtualizer.getStrengthSupported()) {
@@ -108,6 +108,10 @@
 
     //Test case 1.1: test properties
     public void test1_1Properties() throws Exception {
+        if (!isVirtualizerAvailable()) {
+            return;
+        }
+
         getVirtualizer(0);
         try {
             Virtualizer.Settings settings = mVirtualizer.getProperties();
@@ -141,6 +145,10 @@
 
     //Test case 1.2: test setStrength() throws exception after release
     public void test1_2SetStrengthAfterRelease() throws Exception {
+        if (!isVirtualizerAvailable()) {
+            return;
+        }
+
         getVirtualizer(0);
         mVirtualizer.release();
         try {
@@ -158,6 +166,10 @@
 
     //Test case 2.0: test setEnabled() and getEnabled() in valid state
     public void test2_0SetEnabledGetEnabled() throws Exception {
+        if (!isVirtualizerAvailable()) {
+            return;
+        }
+
         getVirtualizer(0);
         try {
             mVirtualizer.setEnabled(true);
@@ -173,6 +185,10 @@
 
     //Test case 2.1: test setEnabled() throws exception after release
     public void test2_1SetEnabledAfterRelease() throws Exception {
+        if (!isVirtualizerAvailable()) {
+            return;
+        }
+
         getVirtualizer(0);
         mVirtualizer.release();
         try {
@@ -190,6 +206,10 @@
 
     //Test case 3.0: test control status listener
     public void test3_0ControlStatusListener() throws Exception {
+        if (!isVirtualizerAvailable()) {
+            return;
+        }
+
         synchronized(mLock) {
             mHasControl = true;
             mInitialized = false;
@@ -212,6 +232,10 @@
 
     //Test case 3.1: test enable status listener
     public void test3_1EnableStatusListener() throws Exception {
+        if (!isVirtualizerAvailable()) {
+            return;
+        }
+
         synchronized(mLock) {
             mInitialized = false;
             createListenerLooper(false, true, false);
@@ -236,6 +260,10 @@
 
     //Test case 3.2: test parameter changed listener
     public void test3_2ParameterChangedListener() throws Exception {
+        if (!isVirtualizerAvailable()) {
+            return;
+        }
+
         synchronized(mLock) {
             mInitialized = false;
             createListenerLooper(false, false, true);
diff --git a/tests/tests/media/src/android/media/cts/VisualizerTest.java b/tests/tests/media/src/android/media/cts/VisualizerTest.java
index e2a9fdd..8c91e9b 100644
--- a/tests/tests/media/src/android/media/cts/VisualizerTest.java
+++ b/tests/tests/media/src/android/media/cts/VisualizerTest.java
@@ -24,7 +24,7 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
-public class VisualizerTest extends AndroidTestCase {
+public class VisualizerTest extends PostProcTestBase {
 
     private String TAG = "VisualizerTest";
     private final static int MIN_CAPTURE_RATE_MAX = 10000; // 10Hz
@@ -33,10 +33,6 @@
     private final static int MAX_LOOPER_WAIT_COUNT = 10;
 
     private Visualizer mVisualizer = null;
-    private int mSession = -1;
-    private boolean mInitialized = false;
-    private Looper mLooper = null;
-    private final Object mLock = new Object();
     private byte[] mWaveform = null;
     private byte[] mFft = null;
     private boolean mCaptureWaveform = false;
@@ -53,10 +49,12 @@
 
     //Test case 0.0: test constructor and release
     public void test0_0ConstructorAndRelease() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
         Visualizer visualizer = null;
-         try {
+        try {
             visualizer = new Visualizer(0);
-            assertNotNull("could not create Visualizer", visualizer);
         } catch (IllegalArgumentException e) {
             fail("Visualizer not found");
         } catch (UnsupportedOperationException e) {
@@ -75,6 +73,9 @@
 
     //Test case 1.0: capture rates
     public void test1_0CaptureRates() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
         getVisualizer(0);
         try {
             int captureRate = mVisualizer.getMaxCaptureRate();
@@ -94,6 +95,9 @@
 
     //Test case 1.1: test capture size
     public void test1_1CaptureSize() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
         getVisualizer(0);
         try {
             int[] range = mVisualizer.getCaptureSizeRange();
@@ -124,6 +128,9 @@
 
     //Test case 2.0: test cature in polling mode
     public void test2_0PollingCapture() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
         try {
             getVisualizer(0);
             mVisualizer.setEnabled(true);
@@ -151,6 +158,9 @@
 
     //Test case 2.1: test capture with listener
     public void test2_1ListenerCapture() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
         try {
             getVisualizer(0);
             synchronized(mLock) {
diff --git a/tests/tests/media/src/android/media/cts/Vp8CodecTestBase.java b/tests/tests/media/src/android/media/cts/Vp8CodecTestBase.java
index 5e38842..586b9ef 100644
--- a/tests/tests/media/src/android/media/cts/Vp8CodecTestBase.java
+++ b/tests/tests/media/src/android/media/cts/Vp8CodecTestBase.java
@@ -335,11 +335,11 @@
     }
 
     /**
-     * Converts (interleaves) YUV420 planar to NV12 (if hw) or NV21 (if sw).
+     * Converts (interleaves) YUV420 planar to NV12.
      * Assumes packed, macroblock-aligned frame with no cropping
-     * (visible/coded row length == stride).  Swap U/V if |sw|.
+     * (visible/coded row length == stride).
      */
-    private static byte[] YUV420ToNV(int width, int height, byte[] yuv, boolean sw) {
+    private static byte[] YUV420ToNV(int width, int height, byte[] yuv) {
         byte[] nv = new byte[yuv.length];
         // Y plane we just copy.
         System.arraycopy(yuv, 0, nv, 0, width * height);
@@ -348,17 +348,9 @@
         int u_offset = width * height;
         int v_offset = u_offset + u_offset / 4;
         int nv_offset = width * height;
-        if (sw) {
-            for (int i = 0; i < width * height / 4; i++) {
-                nv[nv_offset++] = yuv[v_offset++];
-                nv[nv_offset++] = yuv[u_offset++];
-            }
-        }
-        else {
-            for (int i = 0; i < width * height / 4; i++) {
-                nv[nv_offset++] = yuv[u_offset++];
-                nv[nv_offset++] = yuv[v_offset++];
-            }
+        for (int i = 0; i < width * height / 4; i++) {
+            nv[nv_offset++] = yuv[u_offset++];
+            nv[nv_offset++] = yuv[v_offset++];
         }
         return nv;
     }
@@ -788,7 +780,7 @@
             // Convert YUV420 to NV12 if necessary
             if (mProperties.colorFormat != CodecCapabilities.COLOR_FormatYUV420Planar) {
                 return YUV420ToNV(mStreamParams.frameWidth, mStreamParams.frameHeight,
-                        mSrcFrame, mProperties.isGoogleSwCodec());
+                        mSrcFrame);
             } else {
                 return mSrcFrame;
             }
@@ -1390,7 +1382,7 @@
                     // Convert YUV420 to NV12 if necessary
                     if (properties.colorFormat != CodecCapabilities.COLOR_FormatYUV420Planar) {
                         srcFrame = YUV420ToNV(streamParams.frameWidth, streamParams.frameHeight,
-                                srcFrame, properties.isGoogleSwCodec());
+                                srcFrame);
                     }
                 }
 
@@ -1652,8 +1644,7 @@
                     // Convert YUV420 to NV12 if necessary
                     if (codecProperties[i].colorFormat !=
                             CodecCapabilities.COLOR_FormatYUV420Planar) {
-                        srcFrame[i] = YUV420ToNV(params.frameWidth, params.frameHeight, srcFrame[i],
-                                codecProperties[i].isGoogleSwCodec());
+                        srcFrame[i] = YUV420ToNV(params.frameWidth, params.frameHeight, srcFrame[i]);
                     }
                 }
 
diff --git a/tests/tests/nativemedia/sl/Android.mk b/tests/tests/nativemedia/sl/Android.mk
index 5b34b3d..48b816c 100644
--- a/tests/tests/nativemedia/sl/Android.mk
+++ b/tests/tests/nativemedia/sl/Android.mk
@@ -10,6 +10,9 @@
 LOCAL_MODULE := $(test_executable)
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 LOCAL_C_INCLUDES := \
     bionic \
diff --git a/tests/tests/nativemedia/xa/Android.mk b/tests/tests/nativemedia/xa/Android.mk
index 6995bc0..ace315a 100644
--- a/tests/tests/nativemedia/xa/Android.mk
+++ b/tests/tests/nativemedia/xa/Android.mk
@@ -10,6 +10,9 @@
 LOCAL_MODULE:= $(test_executable)
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
 
 LOCAL_C_INCLUDES := \
     bionic \
diff --git a/tests/tests/net/src/android/net/wifi/cts/NsdManagerTest.java b/tests/tests/net/src/android/net/wifi/cts/NsdManagerTest.java
index d1e4c44..d434728 100644
--- a/tests/tests/net/src/android/net/wifi/cts/NsdManagerTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/NsdManagerTest.java
@@ -356,7 +356,7 @@
         assertTrue(lastEvent.mInfo.getPort() == localPort);
         assertTrue(eventCacheSize() == 1);
 
-        assertTrue(checkForAdditionalEvents());
+        checkForAdditionalEvents();
         clearEventCache();
 
         // Unregister the service
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
index 7faea64..152789c 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
@@ -28,6 +28,7 @@
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiManager.TxPacketCountListener;
 import android.net.wifi.WifiManager.WifiLock;
+import android.os.SystemClock;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
@@ -36,6 +37,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
 public class WifiManagerTest extends AndroidTestCase {
@@ -46,7 +48,7 @@
     private WifiManager mWifiManager;
     private WifiLock mWifiLock;
     private static MySync mMySync;
-    private List<ScanResult> mScanResult = null;
+    private List<ScanResult> mScanResults = null;
     private NetworkInfo mNetworkInfo;
 
     // Please refer to WifiManager
@@ -66,6 +68,10 @@
     private static final int TIMEOUT_MSEC = 6000;
     private static final int WAIT_MSEC = 60;
     private static final int DURATION = 10000;
+    private static final int WIFI_SCAN_TEST_INTERVAL_MILLIS = 60 * 1000;
+    private static final int WIFI_SCAN_TEST_CACHE_DELAY_MILLIS = 3 * 60 * 1000;
+    private static final int WIFI_SCAN_TEST_ITERATIONS = 5;
+
     private IntentFilter mIntentFilter;
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
@@ -74,9 +80,9 @@
             if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
                 synchronized (mMySync) {
                     if (mWifiManager.getScanResults() != null) {
-                        mScanResult = mWifiManager.getScanResults();
+                        mScanResults = mWifiManager.getScanResults();
                         mMySync.expectedState = STATE_SCAN_RESULTS_AVAILABLE;
-                        mScanResult = mWifiManager.getScanResults();
+                        mScanResults = mWifiManager.getScanResults();
                         mMySync.notifyAll();
                     }
                 }
@@ -207,8 +213,9 @@
     private void assertDisableOthers(WifiConfiguration wifiConfiguration, boolean disableOthers) {
         for (WifiConfiguration w : mWifiManager.getConfiguredNetworks()) {
             if ((!w.SSID.equals(wifiConfiguration.SSID)) && w.status != Status.CURRENT) {
-                if (disableOthers)
+                if (disableOthers) {
                     assertEquals(Status.DISABLED, w.status);
+                }
             }
         }
     }
@@ -261,6 +268,46 @@
     }
 
     /**
+     * Test WiFi scan timestamp - fails when WiFi scan timestamps are inconsistent with
+     * {@link SystemClock#elapsedRealtime()} on device.<p>
+     * To run this test in cts-tradefed:
+     * run cts --class android.net.wifi.cts.WifiManagerTest --method testWifiScanTimestamp
+     */
+    public void testWifiScanTimestamp() throws Exception {
+        if (!WifiFeature.isWifiSupported(getContext())) {
+            Log.d(TAG, "Skipping test as WiFi is not supported");
+            return;
+        }
+        if (!mWifiManager.isWifiEnabled()) {
+            setWifiEnabled(true);
+        }
+        // Scan multiple times to make sure scan timestamps increase with device timestamp.
+        for (int i = 0; i < WIFI_SCAN_TEST_ITERATIONS; ++i) {
+            startScan();
+            // Make sure at least one AP is found.
+            assertFalse("empty scan results!", mScanResults.isEmpty());
+            long nowMillis = SystemClock.elapsedRealtime();
+            // Keep track of how many APs are fresh in one scan.
+            int numFreshAps = 0;
+            for (ScanResult result : mScanResults) {
+                long scanTimeMillis = TimeUnit.MICROSECONDS.toMillis(result.timestamp);
+                if (Math.abs(nowMillis - scanTimeMillis)  < WIFI_SCAN_TEST_CACHE_DELAY_MILLIS) {
+                    numFreshAps++;
+                }
+            }
+            // At least half of the APs in the scan should be fresh.
+            int numTotalAps = mScanResults.size();
+            String msg = "Stale AP count: " + (numTotalAps - numFreshAps) + ", fresh AP count: "
+                    + numFreshAps;
+            assertTrue(msg, numFreshAps * 2 >= mScanResults.size());
+            if (i < WIFI_SCAN_TEST_ITERATIONS - 1) {
+                // Wait before running next iteration.
+                Thread.sleep(WIFI_SCAN_TEST_INTERVAL_MILLIS);
+            }
+        }
+    }
+
+    /**
      * test point of wifiManager NetWork:
      * 1.add NetWork
      * 2.update NetWork
@@ -275,6 +322,7 @@
             // skip the test if WiFi is not supported
             return;
         }
+
         // store the list of enabled networks, so they can be re-enabled after test completes
         Set<String> enabledSsids = getEnabledNetworks(mWifiManager.getConfiguredNetworks());
         try {
@@ -307,11 +355,6 @@
             wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos);
             assertDisableOthers(wifiConfiguration, disableOthers);
             assertEquals(Status.ENABLED, wifiConfiguration.status);
-            disableOthers = true;
-
-            assertTrue(mWifiManager.enableNetwork(netId, disableOthers));
-            wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos);
-            assertDisableOthers(wifiConfiguration, disableOthers);
 
             assertTrue(mWifiManager.disableNetwork(netId));
             wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos);
diff --git a/tests/tests/os/jni/Android.mk b/tests/tests/os/jni/Android.mk
index 3d3bc33..32a5a9c 100644
--- a/tests/tests/os/jni/Android.mk
+++ b/tests/tests/os/jni/Android.mk
@@ -25,7 +25,8 @@
 		CtsOsJniOnLoad.cpp \
 		android_os_cts_CpuInstructions.cpp.arm \
 		android_os_cts_TaggedPointer.cpp \
-		android_os_cts_OSFeatures.cpp
+		android_os_cts_OSFeatures.cpp \
+		android_os_cts_NoExecutePermissionTest.cpp
 
 LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
 
diff --git a/tests/tests/os/jni/CtsOsJniOnLoad.cpp b/tests/tests/os/jni/CtsOsJniOnLoad.cpp
index c6b88f5..3920915 100644
--- a/tests/tests/os/jni/CtsOsJniOnLoad.cpp
+++ b/tests/tests/os/jni/CtsOsJniOnLoad.cpp
@@ -25,6 +25,8 @@
 
 extern int register_android_os_cts_OSFeatures(JNIEnv*);
 
+extern int register_android_os_cts_NoExecutePermissionTest(JNIEnv*);
+
 jint JNI_OnLoad(JavaVM *vm, void *reserved) {
     JNIEnv *env = NULL;
 
@@ -48,5 +50,9 @@
         return JNI_ERR;
     }
 
+    if (register_android_os_cts_NoExecutePermissionTest(env)) {
+        return JNI_ERR;
+    }
+
     return JNI_VERSION_1_4;
 }
diff --git a/tests/tests/os/jni/android_os_cts_NoExecutePermissionTest.cpp b/tests/tests/os/jni/android_os_cts_NoExecutePermissionTest.cpp
new file mode 100644
index 0000000..e30599c
--- /dev/null
+++ b/tests/tests/os/jni/android_os_cts_NoExecutePermissionTest.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <jni.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <cutils/log.h>
+#include <inttypes.h>
+
+static jboolean isAddressExecutable(uintptr_t address) {
+    char line[1024];
+    jboolean retval = false;
+    FILE *fp = fopen("/proc/self/maps", "re");
+    if (fp == NULL) {
+        ALOGE("Unable to open /proc/self/maps: %s", strerror(errno));
+        return false;
+    }
+    while(fgets(line, sizeof(line), fp) != NULL) {
+        uintptr_t start;
+        uintptr_t end;
+        char permissions[10];
+        int scan = sscanf(line, "%" SCNxPTR "-%" SCNxPTR " %9s ", &start, &end, permissions);
+        if ((scan == 3) && (start <= address) && (address < end)) {
+            retval = (permissions[2] == 'x');
+            break;
+        }
+    }
+    fclose(fp);
+    return retval;
+}
+
+static jboolean android_os_cts_NoExecutePermissionTest_isMyCodeExecutable(JNIEnv*, jobject)
+{
+    return isAddressExecutable((uintptr_t) __builtin_return_address(0));
+}
+
+static jboolean android_os_cts_NoExecutePermissionTest_isStackExecutable(JNIEnv*, jobject)
+{
+    unsigned int foo;
+    return isAddressExecutable((uintptr_t) &foo);
+}
+
+
+static jboolean android_os_cts_NoExecutePermissionTest_isHeapExecutable(JNIEnv*, jobject)
+{
+    unsigned int* foo = (unsigned int *) malloc(sizeof(unsigned int));
+    if (foo == NULL) {
+        ALOGE("Unable to allocate memory");
+        return false;
+    }
+    jboolean result = isAddressExecutable((uintptr_t) foo);
+    free(foo);
+    return result;
+}
+
+static JNINativeMethod gMethods[] = {
+    {  "isMyCodeExecutable", "()Z",
+            (void *) android_os_cts_NoExecutePermissionTest_isMyCodeExecutable  },
+    {  "isStackExecutable", "()Z",
+            (void *) android_os_cts_NoExecutePermissionTest_isStackExecutable  },
+    {  "isHeapExecutable", "()Z",
+            (void *) android_os_cts_NoExecutePermissionTest_isHeapExecutable  }
+};
+
+int register_android_os_cts_NoExecutePermissionTest(JNIEnv* env)
+{
+    jclass clazz = env->FindClass("android/os/cts/NoExecutePermissionTest");
+
+    return env->RegisterNatives(clazz, gMethods,
+            sizeof(gMethods) / sizeof(JNINativeMethod));
+}
diff --git a/tests/tests/os/src/android/os/cts/BuildTest.java b/tests/tests/os/src/android/os/cts/BuildTest.java
index 08db484..26b07f1 100644
--- a/tests/tests/os/src/android/os/cts/BuildTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildTest.java
@@ -18,8 +18,13 @@
 
 
 import android.os.Build;
+import android.os.SystemProperties;
+
+import dalvik.system.VMRuntime;
 
 import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Scanner;
 import java.util.regex.Pattern;
 
@@ -27,59 +32,76 @@
 
 public class BuildTest extends TestCase {
 
-    private static final String RO_PRODUCT_CPU_ABI = "ro.product.cpu.abi";
-
-    private static final String RO_PRODUCT_CPU_ABI2 = "ro.product.cpu.abi2";
+    private static final String RO_PRODUCT_CPU_ABILIST = "ro.product.cpu.abilist";
+    private static final String RO_PRODUCT_CPU_ABILIST32 = "ro.product.cpu.abilist32";
+    private static final String RO_PRODUCT_CPU_ABILIST64 = "ro.product.cpu.abilist64";
 
     /** Tests that check the values of {@link Build#CPU_ABI} and {@link Build#CPU_ABI2}. */
-    public void testCpuAbi() throws IOException {
-        if (CpuFeatures.isArmCpu()) {
-            assertArmCpuAbiConstants();
+    public void testCpuAbi() throws Exception {
+        testCpuAbiCommon();
+        if (VMRuntime.getRuntime().is64Bit()) {
+            testCpuAbi64();
+        } else {
+            testCpuAbi32();
         }
     }
 
-    private void assertArmCpuAbiConstants() throws IOException {
-        if (CpuFeatures.isArm7Compatible()) {
-            String cpuAbi = getProperty(RO_PRODUCT_CPU_ABI);
-            String cpuAbi2 = getProperty(RO_PRODUCT_CPU_ABI2);
-            //if CPU_ABI is armv7, CPU_ABI2 is either of {armeabi, NULL}
-            if (cpuAbi.equals(CpuFeatures.ARMEABI_V7)) {
-                String message = "CPU is ARM v7 compatible, so "
-                    + RO_PRODUCT_CPU_ABI  + " must be set to " + CpuFeatures.ARMEABI_V7 + " and "
-                    + RO_PRODUCT_CPU_ABI2 + " must be set to " + CpuFeatures.ARMEABI + " or NULL";
-                assertEquals(message, CpuFeatures.ARMEABI_V7, Build.CPU_ABI);
-                if (cpuAbi2.equals(CpuFeatures.ARMEABI)){
-                    assertEquals(message, cpuAbi2, Build.CPU_ABI2);
-                } else {
-                    assertNoPropertySet(message, RO_PRODUCT_CPU_ABI2);
-                    assertEquals(message, Build.UNKNOWN, Build.CPU_ABI2);
-                }
-            }
-            //if CPU_ABI is x86, then CPU_ABI2 is either of {armeabi, armv7, NULL}
-            else if (cpuAbi.equals(CpuFeatures.X86ABI)) {
-                String message = "CPU is x86 but ARM v7 compatible, so "
-                    + RO_PRODUCT_CPU_ABI  + " must be set to " + CpuFeatures.X86ABI + " and "
-                    + RO_PRODUCT_CPU_ABI2 + " must be set to " + CpuFeatures.ARMEABI + " or "
-                    + CpuFeatures.ARMEABI_V7 + " or NULL";
-                assertEquals(message, CpuFeatures.X86ABI, Build.CPU_ABI);
-                if (cpuAbi2.equals(CpuFeatures.ARMEABI_V7) || cpuAbi2.equals(CpuFeatures.ARMEABI))
-                    assertEquals(message, cpuAbi2, Build.CPU_ABI2);
-                else {
-                    assertNoPropertySet(message, RO_PRODUCT_CPU_ABI2);
-                    assertEquals(message, Build.UNKNOWN, Build.CPU_ABI2);
-                }
-            }
+    private void testCpuAbiCommon() 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));
+
+        List<String> abiList = Arrays.asList(abiListProperty);
+
+        // Every device must support at least one 32 bit ABI.
+        assertTrue(Build.SUPPORTED_32_BIT_ABIS.length > 0);
+
+        // Every supported 32 bit ABI must be present in Build.SUPPORTED_ABIS.
+        for (String abi : Build.SUPPORTED_32_BIT_ABIS) {
+            assertTrue(abiList.contains(abi));
+            assertFalse(VMRuntime.is64BitAbi(abi));
         }
-        else {
-            String message = "CPU is not ARM v7 compatible. "
-                    + RO_PRODUCT_CPU_ABI  + " must be set to " + CpuFeatures.ARMEABI + " and "
-                    + RO_PRODUCT_CPU_ABI2 + " must not be set.";
-            assertProperty(message, RO_PRODUCT_CPU_ABI, CpuFeatures.ARMEABI);
-            assertNoPropertySet(message, RO_PRODUCT_CPU_ABI2);
-            assertEquals(message, CpuFeatures.ARMEABI, Build.CPU_ABI);
-            assertEquals(message, Build.UNKNOWN, Build.CPU_ABI2);
+
+        // Every supported 64 bit ABI must be present in Build.SUPPORTED_ABIS.
+        for (String abi : Build.SUPPORTED_64_BIT_ABIS) {
+            assertTrue(abiList.contains(abi));
+            assertTrue(VMRuntime.is64BitAbi(abi));
+        }
+
+        // Build.CPU_ABI and Build.CPU_ABI2 must be present in Build.SUPPORTED_ABIS.
+        assertTrue(abiList.contains(Build.CPU_ABI));
+        if (!Build.CPU_ABI2.isEmpty()) {
+            assertTrue(abiList.contains(Build.CPU_ABI2));
         }
     }
+
+    private void testCpuAbi32() throws Exception {
+        List<String> abi32 = Arrays.asList(Build.SUPPORTED_32_BIT_ABIS);
+        assertTrue(abi32.contains(Build.CPU_ABI));
+
+        if (!Build.CPU_ABI2.isEmpty()) {
+            assertTrue(abi32.contains(Build.CPU_ABI2));
+        }
+    }
+
+    private void testCpuAbi64() {
+        List<String> abi64 = Arrays.asList(Build.SUPPORTED_64_BIT_ABIS);
+        assertTrue(abi64.contains(Build.CPU_ABI));
+
+        if (!Build.CPU_ABI2.isEmpty()) {
+            assertTrue(abi64.contains(Build.CPU_ABI2));
+        }
+    }
+
+    private String[] getStringList(String property) throws IOException {
+        String value = getProperty(property);
+        if (value.isEmpty()) {
+            return new String[0];
+        } else {
+            return value.split(",");
+        }
+    }
+
     /**
      * @param property name passed to getprop
      */
diff --git a/tests/tests/os/src/android/os/cts/BuildVersionTest.java b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
index 6069ee6..e335901 100644
--- a/tests/tests/os/src/android/os/cts/BuildVersionTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
@@ -28,7 +28,8 @@
 public class BuildVersionTest extends TestCase {
 
     private static final String LOG_TAG = "BuildVersionTest";
-    private static final Set<String> EXPECTED_RELEASES = new HashSet<String>(Arrays.asList("5.0"));
+    private static final Set<String> EXPECTED_RELEASES =
+            new HashSet<String>(Arrays.asList("5.0", "5.0.1", "5.0.2"));
     private static final int EXPECTED_SDK = 21;
     private static final String EXPECTED_BUILD_VARIANT = "user";
     private static final String EXPECTED_TAG = "release-keys";
diff --git a/tests/tests/os/src/android/os/cts/NoExecutePermissionTest.java b/tests/tests/os/src/android/os/cts/NoExecutePermissionTest.java
index 43afb53..224ab46 100644
--- a/tests/tests/os/src/android/os/cts/NoExecutePermissionTest.java
+++ b/tests/tests/os/src/android/os/cts/NoExecutePermissionTest.java
@@ -28,45 +28,26 @@
  */
 public class NoExecutePermissionTest extends TestCase {
 
-    public void testNoExecutePermission() throws FileNotFoundException {
+    static {
+        System.loadLibrary("ctsos_jni");
+    }
+
+    public void testNoExecuteStack() {
         if (!cpuHasNxSupport()) {
             return;
         }
+        assertFalse(isStackExecutable());
+    }
 
-        String heapPermissions = null;
-        String stackPermissions = null;
-
-        Scanner scanner = null;
-        try {
-            scanner = new Scanner(new File("/proc/self/maps"));
-            while (scanner.hasNextLine()) {
-                String line = scanner.nextLine().trim();
-                String[] fields = line.split("\\s+");
-
-                // Sample line:
-                // 0001d000-00024000 rw-p 00000000 00:00 0          [heap]
-                if (fields != null && fields.length >= 1) {
-                    String permissions = fields[1];
-                    if (fields.length >= 6) {
-                        String tag = fields[5];
-                        if ("[heap]".equals(tag)) {
-                            heapPermissions = permissions;
-                        } else if ("[stack]".equals(tag)) {
-                            stackPermissions = permissions;
-                        }
-                    }
-                }
-            }
-        } finally {
-            if (scanner != null) {
-                scanner.close();
-            }
+    public void testNoExecuteHeap() {
+        if (!cpuHasNxSupport()) {
+            return;
         }
+        assertFalse(isHeapExecutable());
+    }
 
-        if (heapPermissions != null) {
-            assertEquals("NX (No Execute) not enabled for heap", "rw-p", heapPermissions);
-        }
-        assertEquals("NX (No Execute) not enabled for stack", "rw-p", stackPermissions);
+    public void testExecuteCode() {
+        assertTrue(isMyCodeExecutable());
     }
 
     private static boolean cpuHasNxSupport() {
@@ -84,4 +65,8 @@
         // have NX support.
         return true;
     }
+
+    private static native boolean isStackExecutable();
+    private static native boolean isHeapExecutable();
+    private static native boolean isMyCodeExecutable();
 }
diff --git a/tests/tests/rscpp/Android.mk b/tests/tests/rscpp/Android.mk
index 60adc05..0eb32b5 100644
--- a/tests/tests/rscpp/Android.mk
+++ b/tests/tests/rscpp/Android.mk
@@ -31,7 +31,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
 LOCAL_JNI_SHARED_LIBRARIES := librscpptest_jni
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/tests/rscpp/src/android/cts/rscpp/RS3DLUTTest.java b/tests/tests/rscpp/src/android/cts/rscpp/RS3DLUTTest.java
index 470593c..f278835 100644
--- a/tests/tests/rscpp/src/android/cts/rscpp/RS3DLUTTest.java
+++ b/tests/tests/rscpp/src/android/cts/rscpp/RS3DLUTTest.java
@@ -39,7 +39,6 @@
         RSUtils.genRandom(0x419144, 255, 1, -128, baseAlloc);
         int[] colorCube = new int[lutSize * lutSize * lutSize * 4];
         RSUtils.genRandom(0x555007, 255, 1, -128, colorCube);
-        RenderScript mRS = RenderScript.create(getContext());
         byte[] byteAlloc = new byte[X * Y * 4];
         byte[] byteColorCube = new byte[lutSize * lutSize * lutSize * 4];
         for (int i = 0; i < X * Y * 4; i++) {
@@ -49,7 +48,6 @@
             byteColorCube[i] = (byte)colorCube[i];
         }
 
-
         Type.Builder build = new Type.Builder(mRS, Element.RGBA_8888(mRS));
         build.setX(X);
         build.setY(Y);
@@ -58,10 +56,10 @@
         rsInput.copyFromUnchecked(byteAlloc);
 
         Type.Builder buildCube = new Type.Builder(mRS, Element.RGBA_8888(mRS));
-        build.setX(lutSize);
-        build.setY(lutSize);
-        build.setZ(lutSize);
-        Allocation cube = Allocation.createTyped(mRS, build.create());
+        buildCube.setX(lutSize);
+        buildCube.setY(lutSize);
+        buildCube.setZ(lutSize);
+        Allocation cube = Allocation.createTyped(mRS, buildCube.create());
         cube.copyFromUnchecked(byteColorCube);
         ScriptIntrinsic3DLUT lut = ScriptIntrinsic3DLUT.create(mRS, Element.RGBA_8888(mRS));
 
@@ -70,12 +68,12 @@
 
         byte[] nativeByteAlloc = new byte[X * Y * 4];
         lutTest(this.getContext().getCacheDir().toString(), X, Y, lutSize, byteAlloc, byteColorCube, nativeByteAlloc);
-        rsOutput.copyTo(byteAlloc);
 
-        for (int i = 0; i < X * Y * 4; i++) {
-            assertTrue(byteAlloc[i] == nativeByteAlloc[i]);
-        }
+        Allocation rsCppOutput = Allocation.createTyped(mRS, build.create());
+        rsCppOutput.copyFromUnchecked(nativeByteAlloc);
+        mVerify.invoke_verify(rsOutput, rsCppOutput, rsInput);
+        checkForErrors();
 
     }
 
-}
\ No newline at end of file
+}
diff --git a/tests/tests/rscpp/src/android/cts/rscpp/RSBlendTest.java b/tests/tests/rscpp/src/android/cts/rscpp/RSBlendTest.java
index 025d470..1c6dc51 100644
--- a/tests/tests/rscpp/src/android/cts/rscpp/RSBlendTest.java
+++ b/tests/tests/rscpp/src/android/cts/rscpp/RSBlendTest.java
@@ -36,7 +36,6 @@
         for (int iter = 0; iter < 15; iter++) {
             int[] baseAlloc = new int[X * Y * 4];
             RSUtils.genRandom(0x789321, 255, 1, -128, baseAlloc);
-            RenderScript mRS = RenderScript.create(getContext());
             byte[] byteAlloc = new byte[X * Y * 4];
             for (int i = 0; i < X * Y * 4; i++) {
                 byteAlloc[i] = (byte)baseAlloc[i];
@@ -110,12 +109,11 @@
             }
 
             blendTest(this.getContext().getCacheDir().toString(), X, Y, byteAlloc, byteAlloc2, iter);
-            rsOutput.copyTo(byteAlloc);
-            for (int i = 0; i < X * Y * 4; i++) {
-                assertTrue(byteAlloc[i] == byteAlloc2[i]);
-            }
 
-            mRS.destroy();
+            Allocation rsCppOutput = Allocation.createTyped(mRS, build.create());
+            rsCppOutput.copyFromUnchecked(byteAlloc2);
+            mVerify.invoke_verify(rsOutput, rsCppOutput, rsInput);
+            checkForErrors();
         }
 
     }
diff --git a/tests/tests/rscpp/src/android/cts/rscpp/RSBlurTest.java b/tests/tests/rscpp/src/android/cts/rscpp/RSBlurTest.java
index 70f15fc..34bb7ad 100644
--- a/tests/tests/rscpp/src/android/cts/rscpp/RSBlurTest.java
+++ b/tests/tests/rscpp/src/android/cts/rscpp/RSBlurTest.java
@@ -35,7 +35,6 @@
     public void testRSBlurOneChannel() {
         int[] baseAlloc = new int[X * Y];
         RSUtils.genRandom(0x1DEFF, 255, 1, -128, baseAlloc);
-        RenderScript mRS = RenderScript.create(getContext());
         byte[] byteAlloc = new byte[X * Y];
         for (int i = 0; i < X * Y; i++) {
             byteAlloc[i] = (byte)baseAlloc[i];
@@ -54,19 +53,17 @@
 
         byte[] nativeByteAlloc = new byte[X * Y];
         blurTest(this.getContext().getCacheDir().toString(), X, Y, byteAlloc, nativeByteAlloc, true);
-        rsOutput.copyTo(byteAlloc);
 
-        for (int i = 0; i < X * Y; i++) {
-            assertTrue(byteAlloc[i] == nativeByteAlloc[i]);
-        }
-
+        Allocation rsCppOutput = Allocation.createTyped(mRS, build.create());
+        rsCppOutput.copyFromUnchecked(nativeByteAlloc);
+        mVerify.invoke_verify(rsOutput, rsCppOutput, rsInput);
+        checkForErrors();
     }
 
 
     public void testRSBlurFourChannels() {
         int[] baseAlloc = new int[X * Y * 4];
         RSUtils.genRandom(0xFAFADE10, 255, 1, -128, baseAlloc);
-        RenderScript mRS = RenderScript.create(getContext());
         byte[] byteAlloc = new byte[X * Y * 4];
         for (int i = 0; i < X * Y * 4; i++) {
             byteAlloc[i] = (byte)baseAlloc[i];
@@ -85,13 +82,12 @@
 
         byte[] nativeByteAlloc = new byte[X * Y * 4];
         blurTest(this.getContext().getCacheDir().toString(), X, Y, byteAlloc, nativeByteAlloc, false);
-        rsOutput.copyTo(byteAlloc);
 
-        for (int i = 0; i < X * Y * 4; i++) {
-            assertTrue(byteAlloc[i] == nativeByteAlloc[i]);
-        }
-
+        Allocation rsCppOutput = Allocation.createTyped(mRS, build.create());
+        rsCppOutput.copyFromUnchecked(nativeByteAlloc);
+        mVerify.invoke_verify(rsOutput, rsCppOutput, rsInput);
+        checkForErrors();
     }
 
 
-}
\ No newline at end of file
+}
diff --git a/tests/tests/rscpp/src/android/cts/rscpp/RSColorMatrixTest.java b/tests/tests/rscpp/src/android/cts/rscpp/RSColorMatrixTest.java
index efa28bb..5260ed9 100644
--- a/tests/tests/rscpp/src/android/cts/rscpp/RSColorMatrixTest.java
+++ b/tests/tests/rscpp/src/android/cts/rscpp/RSColorMatrixTest.java
@@ -35,7 +35,6 @@
     public void testRSColorMatrix0() {
         int[] baseAlloc = new int[X * Y * 4];
         RSUtils.genRandom(0x251107, 255, 1, -128, baseAlloc);
-        RenderScript mRS = RenderScript.create(getContext());
         byte[] byteAlloc = new byte[X * Y * 4];
         for (int i = 0; i < X * Y * 4; i++) {
             byteAlloc[i] = (byte)baseAlloc[i];
@@ -66,18 +65,16 @@
 
         byte[] nativeByteAlloc = new byte[X * Y * 4];
         colorMatrixTest(this.getContext().getCacheDir().toString(), X, Y, byteAlloc, nativeByteAlloc, coeffs, 0);
-        rsOutput.copyTo(byteAlloc);
 
-        for (int i = 0; i < X * Y * 4; i++) {
-            assertTrue(byteAlloc[i] == nativeByteAlloc[i]);
-        }
-
+        Allocation rsCppOutput = Allocation.createTyped(mRS, build.create());
+        rsCppOutput.copyFromUnchecked(nativeByteAlloc);
+        mVerify.invoke_verify(rsOutput, rsCppOutput, rsInput);
+        checkForErrors();
     }
 
     public void testRSColorMatrix1() {
         int[] baseAlloc = new int[X * Y * 4];
         RSUtils.genRandom(0x251106, 255, 1, -128, baseAlloc);
-        RenderScript mRS = RenderScript.create(getContext());
         byte[] byteAlloc = new byte[X * Y * 4];
         for (int i = 0; i < X * Y * 4; i++) {
             byteAlloc[i] = (byte)baseAlloc[i];
@@ -98,18 +95,17 @@
 
         byte[] nativeByteAlloc = new byte[X * Y * 4];
         colorMatrixTest(this.getContext().getCacheDir().toString(), X, Y, byteAlloc, nativeByteAlloc, coeffs, 1);
-        rsOutput.copyTo(byteAlloc);
 
-        for (int i = 0; i < X * Y * 4; i++) {
-            assertTrue(byteAlloc[i] == nativeByteAlloc[i]);
-        }
+        Allocation rsCppOutput = Allocation.createTyped(mRS, build.create());
+        rsCppOutput.copyFromUnchecked(nativeByteAlloc);
+        mVerify.invoke_verify(rsOutput, rsCppOutput, rsInput);
+        checkForErrors();
 
     }
 
     public void testRSColorMatrix2() {
         int[] baseAlloc = new int[X * Y * 4];
         RSUtils.genRandom(0x251105, 255, 1, -128, baseAlloc);
-        RenderScript mRS = RenderScript.create(getContext());
         byte[] byteAlloc = new byte[X * Y * 4];
         for (int i = 0; i < X * Y * 4; i++) {
             byteAlloc[i] = (byte)baseAlloc[i];
@@ -134,18 +130,17 @@
 
         byte[] nativeByteAlloc = new byte[X * Y * 4];
         colorMatrixTest(this.getContext().getCacheDir().toString(), X, Y, byteAlloc, nativeByteAlloc, coeffs, 2);
-        rsOutput.copyTo(byteAlloc);
 
-        for (int i = 0; i < X * Y * 4; i++) {
-            assertTrue(byteAlloc[i] == nativeByteAlloc[i]);
-        }
+        Allocation rsCppOutput = Allocation.createTyped(mRS, build.create());
+        rsCppOutput.copyFromUnchecked(nativeByteAlloc);
+        mVerify.invoke_verify(rsOutput, rsCppOutput, rsInput);
+        checkForErrors();
 
     }
 
     public void testRSColorMatrix3() {
         int[] baseAlloc = new int[X * Y * 4];
         RSUtils.genRandom(0x251104, 255, 1, -128, baseAlloc);
-        RenderScript mRS = RenderScript.create(getContext());
         byte[] byteAlloc = new byte[X * Y * 4];
         for (int i = 0; i < X * Y * 4; i++) {
             byteAlloc[i] = (byte)baseAlloc[i];
@@ -166,18 +161,17 @@
 
         byte[] nativeByteAlloc = new byte[X * Y * 4];
         colorMatrixTest(this.getContext().getCacheDir().toString(), X, Y, byteAlloc, nativeByteAlloc, coeffs, 3);
-        rsOutput.copyTo(byteAlloc);
 
-        for (int i = 0; i < X * Y * 4; i++) {
-            assertTrue(byteAlloc[i] == nativeByteAlloc[i]);
-        }
+        Allocation rsCppOutput = Allocation.createTyped(mRS, build.create());
+        rsCppOutput.copyFromUnchecked(nativeByteAlloc);
+        mVerify.invoke_verify(rsOutput, rsCppOutput, rsInput);
+        checkForErrors();
 
     }
 
     public void testRSColorMatrix4() {
         int[] baseAlloc = new int[X * Y * 4];
         RSUtils.genRandom(0x251103, 255, 1, -128, baseAlloc);
-        RenderScript mRS = RenderScript.create(getContext());
         byte[] byteAlloc = new byte[X * Y * 4];
         for (int i = 0; i < X * Y * 4; i++) {
             byteAlloc[i] = (byte)baseAlloc[i];
@@ -198,12 +192,12 @@
 
         byte[] nativeByteAlloc = new byte[X * Y * 4];
         colorMatrixTest(this.getContext().getCacheDir().toString(), X, Y, byteAlloc, nativeByteAlloc, coeffs, 4);
-        rsOutput.copyTo(byteAlloc);
 
-        for (int i = 0; i < X * Y * 4; i++) {
-            assertTrue(byteAlloc[i] == nativeByteAlloc[i]);
-        }
+        Allocation rsCppOutput = Allocation.createTyped(mRS, build.create());
+        rsCppOutput.copyFromUnchecked(nativeByteAlloc);
+        mVerify.invoke_verify(rsOutput, rsCppOutput, rsInput);
+        checkForErrors();
 
     }
 
-}
\ No newline at end of file
+}
diff --git a/tests/tests/rscpp/src/android/cts/rscpp/RSConvolveTest.java b/tests/tests/rscpp/src/android/cts/rscpp/RSConvolveTest.java
index 0cd5c79..2a3579e 100644
--- a/tests/tests/rscpp/src/android/cts/rscpp/RSConvolveTest.java
+++ b/tests/tests/rscpp/src/android/cts/rscpp/RSConvolveTest.java
@@ -46,7 +46,6 @@
         coeffs[8] =  .5f;
 
         RSUtils.genRandom(0x1DEFFD0, 255, 1, -128, baseAlloc);
-        RenderScript mRS = RenderScript.create(getContext());
         byte[] byteAlloc = new byte[X * Y];
         for (int i = 0; i < X * Y; i++) {
             byteAlloc[i] = (byte)baseAlloc[i];
@@ -65,12 +64,11 @@
 
         byte[] nativeByteAlloc = new byte[X * Y];
         convolveTest(this.getContext().getCacheDir().toString(), X, Y, byteAlloc, nativeByteAlloc, coeffs, true);
-        rsOutput.copyTo(byteAlloc);
 
-        for (int i = 0; i < X * Y; i++) {
-            assertTrue(byteAlloc[i] == nativeByteAlloc[i]);
-        }
-
+        Allocation rsCppOutput = Allocation.createTyped(mRS, build.create());
+        rsCppOutput.copyFromUnchecked(nativeByteAlloc);
+        mVerify.invoke_verify(rsOutput, rsCppOutput, rsInput);
+        checkForErrors();
     }
 
     public void testConvolve5x5() {
@@ -123,13 +121,13 @@
 
         byte[] nativeByteAlloc = new byte[X * Y];
         convolveTest(this.getContext().getCacheDir().toString(), X, Y, byteAlloc, nativeByteAlloc, coeffs, false);
-        rsOutput.copyTo(byteAlloc);
 
-        for (int i = 0; i < X * Y; i++) {
-            assertTrue(byteAlloc[i] == nativeByteAlloc[i]);
-        }
+        Allocation rsCppOutput = Allocation.createTyped(mRS, build.create());
+        rsCppOutput.copyFromUnchecked(nativeByteAlloc);
+        mVerify.invoke_verify(rsOutput, rsCppOutput, rsInput);
+        checkForErrors();
 
     }
 
 
-}
\ No newline at end of file
+}
diff --git a/tests/tests/rscpp/src/android/cts/rscpp/RSCppTest.java b/tests/tests/rscpp/src/android/cts/rscpp/RSCppTest.java
index b2bf33e..9b09cc7 100644
--- a/tests/tests/rscpp/src/android/cts/rscpp/RSCppTest.java
+++ b/tests/tests/rscpp/src/android/cts/rscpp/RSCppTest.java
@@ -19,23 +19,91 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.test.AndroidTestCase;
-import android.renderscript.*;
+import android.renderscript.RenderScript.RSErrorHandler;
+import android.renderscript.RenderScript.RSMessageHandler;
+import android.renderscript.RSRuntimeException;
+import android.renderscript.RenderScript;
+import android.renderscript.Allocation;
+import android.renderscript.Element;
 import android.util.Log;
 
 public class RSCppTest extends AndroidTestCase {
 
     Context mCtx;
     Resources mRes;
+    RenderScript mRS;
+    protected ScriptC_verify mVerify;
+
+    private int result;
+    private boolean msgHandled;
+
+    private static final int RS_MSG_TEST_PASSED = 100;
+    private static final int RS_MSG_TEST_FAILED = 101;
+
+    RSMessageHandler mRsMessage = new RSMessageHandler() {
+        public void run() {
+            if (result == 0) {
+                switch (mID) {
+                    case RS_MSG_TEST_PASSED:
+                    case RS_MSG_TEST_FAILED:
+                        result = mID;
+                        break;
+                    default:
+                        fail("Got unexpected RS message");
+                        return;
+                }
+            }
+            msgHandled = true;
+        }
+    };
+
+    protected void waitForMessage() {
+        while (!msgHandled) {
+            Thread.yield();
+        }
+    }
+
+    protected boolean FoundError = false;
+    protected RSErrorHandler mRsError = new RSErrorHandler() {
+        public void run() {
+            FoundError = true;
+            Log.e("RSCppCTS", mErrorMessage);
+            throw new RSRuntimeException("Received error " + mErrorNum +
+                                         " message " + mErrorMessage);
+        }
+    };
+
+    protected void checkForErrors() {
+        mRS.finish();
+        mVerify.invoke_checkError();
+        waitForMessage();
+        assertFalse(FoundError);
+        assertTrue(result != RS_MSG_TEST_FAILED);
+    }
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+        result = 0;
+        msgHandled = false;
         mCtx = getContext();
         mRes = mCtx.getResources();
+        mRS = RenderScript.create(mCtx);
+        mRS.setMessageHandler(mRsMessage);
+        mVerify = new ScriptC_verify(mRS);
+        mVerify.set_gAllowedIntError(3);
     }
 
     @Override
     protected void tearDown() throws Exception {
+        if (mVerify != null) {
+            mVerify.destroy();
+            mVerify = null;
+        }
+        if (mRS != null) {
+            mRS.destroy();
+            mRS = null;
+        }
         super.tearDown();
     }
 }
diff --git a/tests/tests/rscpp/src/android/cts/rscpp/RSInitTest.java b/tests/tests/rscpp/src/android/cts/rscpp/RSInitTest.java
index ca6be9c..f6b4251 100644
--- a/tests/tests/rscpp/src/android/cts/rscpp/RSInitTest.java
+++ b/tests/tests/rscpp/src/android/cts/rscpp/RSInitTest.java
@@ -30,10 +30,10 @@
     native boolean initTest(String path);
     public void testRSInit() {
         for (int i = 0; i < 1000; i++) {
-            RenderScript mRS = RenderScript.create(getContext());
-            mRS.destroy();
+            RenderScript mRSt = RenderScript.create(getContext());
+            mRSt.destroy();
             Log.d("rscpptest", "Java iteration " + i);
         }
         assertTrue(initTest(this.getContext().getCacheDir().toString()));
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/rscpp/src/android/cts/rscpp/RSLUTTest.java b/tests/tests/rscpp/src/android/cts/rscpp/RSLUTTest.java
index f1ea040..aa24209 100644
--- a/tests/tests/rscpp/src/android/cts/rscpp/RSLUTTest.java
+++ b/tests/tests/rscpp/src/android/cts/rscpp/RSLUTTest.java
@@ -35,7 +35,6 @@
     public void testRSLUT() {
         int[] baseAlloc = new int[X * Y * 4];
         RSUtils.genRandom(0x72727272, 255, 1, -128, baseAlloc);
-        RenderScript mRS = RenderScript.create(getContext());
         byte[] byteAlloc = new byte[X * Y * 4];
         for (int i = 0; i < X * Y * 4; i++) {
             byteAlloc[i] = (byte)baseAlloc[i];
@@ -58,12 +57,12 @@
 
         byte[] nativeByteAlloc = new byte[X * Y * 4];
         lutTest(this.getContext().getCacheDir().toString().toString(), X, Y, byteAlloc, nativeByteAlloc);
-        rsOutput.copyTo(byteAlloc);
 
-        for (int i = 0; i < X * Y * 4; i++) {
-            assertTrue(byteAlloc[i] == nativeByteAlloc[i]);
-        }
+        Allocation rsCppOutput = Allocation.createTyped(mRS, build.create());
+        rsCppOutput.copyFromUnchecked(nativeByteAlloc);
+        mVerify.invoke_verify(rsOutput, rsCppOutput, rsInput);
+        checkForErrors();
 
     }
 
-}
\ No newline at end of file
+}
diff --git a/tests/tests/rscpp/src/android/cts/rscpp/verify.rs b/tests/tests/rscpp/src/android/cts/rscpp/verify.rs
new file mode 100644
index 0000000..7fd44d3
--- /dev/null
+++ b/tests/tests/rscpp/src/android/cts/rscpp/verify.rs
@@ -0,0 +1,311 @@
+/*
+ * 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.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(android.cts.rscpp)
+
+/* These constants must match those in RSCppTest.java */
+static const int RS_MSG_TEST_PASSED = 100;
+static const int RS_MSG_TEST_FAILED = 101;
+
+int gAllowedIntError = 0;
+static bool hadError = false;
+static int2 errorLoc = {0,0};
+
+
+static bool compare_float(float f1, float f2) {
+    if (fabs(f1-f2) > 0.0001f) {
+        hadError = true;
+        return false;
+    }
+    return true;
+}
+
+static bool verify_float4(rs_allocation in1, rs_allocation in2)
+{
+    uint32_t w = rsAllocationGetDimX(in1);
+    uint32_t h = rsAllocationGetDimY(in1);
+    for (uint32_t y=0; y < h; y++) {
+        for (uint32_t x=0; x < w; x++) {
+            float4 pref = rsGetElementAt_float4(in1, x, y);
+            float4 ptst = rsGetElementAt_float4(in2, x, y);
+            bool e = !compare_float(pref.x, ptst.x);
+            e |= !compare_float(pref.y, ptst.y);
+            e |= !compare_float(pref.z, ptst.z);
+            e |= !compare_float(pref.w, ptst.w);
+            if (e) {
+                errorLoc.x = x;
+                errorLoc.y = y;
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+static bool verify_float3(rs_allocation in1, rs_allocation in2)
+{
+    uint32_t w = rsAllocationGetDimX(in1);
+    uint32_t h = rsAllocationGetDimY(in1);
+    for (uint32_t y=0; y < h; y++) {
+        for (uint32_t x=0; x < w; x++) {
+            float3 pref = rsGetElementAt_float3(in1, x, y);
+            float3 ptst = rsGetElementAt_float3(in2, x, y);
+            bool e = !compare_float(pref.x, ptst.x);
+            e |= !compare_float(pref.y, ptst.y);
+            e |= !compare_float(pref.z, ptst.z);
+            if (e) {
+                errorLoc.x = x;
+                errorLoc.y = y;
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+static bool verify_float2(rs_allocation in1, rs_allocation in2)
+{
+    uint32_t w = rsAllocationGetDimX(in1);
+    uint32_t h = rsAllocationGetDimY(in1);
+    for (uint32_t y=0; y < h; y++) {
+        for (uint32_t x=0; x < w; x++) {
+            float2 pref = rsGetElementAt_float2(in1, x, y);
+            float2 ptst = rsGetElementAt_float2(in2, x, y);
+            bool e = !compare_float(pref.x, ptst.x);
+            e |= !compare_float(pref.y, ptst.y);
+            if (e) {
+                errorLoc.x = x;
+                errorLoc.y = y;
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+static bool verify_float(rs_allocation in1, rs_allocation in2)
+{
+    uint32_t w = rsAllocationGetDimX(in1);
+    uint32_t h = rsAllocationGetDimY(in1);
+    for (uint32_t y=0; y < h; y++) {
+        for (uint32_t x=0; x < w; x++) {
+            float pref = rsGetElementAt_float(in1, x, y);
+            float ptst = rsGetElementAt_float(in2, x, y);
+            bool e = !compare_float(pref, ptst);
+            if (e) {
+                errorLoc.x = x;
+                errorLoc.y = y;
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+static bool verify_uchar4(rs_allocation in1, rs_allocation in2)
+{
+    int merr = 0;
+    uint32_t w = rsAllocationGetDimX(in1);
+    uint32_t h = rsAllocationGetDimY(in1);
+    for (uint32_t y=0; y < h; y++) {
+        for (uint32_t x=0; x < w; x++) {
+            int4 pref = convert_int4(rsGetElementAt_uchar4(in1, x, y));
+            int4 ptst = convert_int4(rsGetElementAt_uchar4(in2, x, y));
+            int4 d = convert_int4(abs(pref - ptst));
+            int e = 0;
+            e = max(e, d.x);
+            e = max(e, d.y);
+            e = max(e, d.z);
+            e = max(e, d.w);
+            if (e > gAllowedIntError) {
+                errorLoc.x = x;
+                errorLoc.y = y;
+                hadError = true;
+                return false;
+            }
+            merr = max(e, merr);
+        }
+    }
+    return true;
+}
+
+static bool verify_uchar3(rs_allocation in1, rs_allocation in2)
+{
+    int merr = 0;
+    uint32_t w = rsAllocationGetDimX(in1);
+    uint32_t h = rsAllocationGetDimY(in1);
+    for (uint32_t y=0; y < h; y++) {
+        for (uint32_t x=0; x < w; x++) {
+            int3 pref = convert_int3(rsGetElementAt_uchar3(in1, x, y));
+            int3 ptst = convert_int3(rsGetElementAt_uchar3(in2, x, y));
+            int3 d = convert_int3(abs(pref - ptst));
+            int e = 0;
+            e = max(e, d.x);
+            e = max(e, d.y);
+            e = max(e, d.z);
+            if (e > gAllowedIntError) {
+                errorLoc.x = x;
+                errorLoc.y = y;
+                hadError = true;
+                return false;
+            }
+            merr = max(e, merr);
+        }
+    }
+    return true;
+}
+
+static bool verify_uchar2(rs_allocation in1, rs_allocation in2)
+{
+    int merr = 0;
+    uint32_t w = rsAllocationGetDimX(in1);
+    uint32_t h = rsAllocationGetDimY(in1);
+    for (uint32_t y=0; y < h; y++) {
+        for (uint32_t x=0; x < w; x++) {
+            int2 pref = convert_int2(rsGetElementAt_uchar2(in1, x, y));
+            int2 ptst = convert_int2(rsGetElementAt_uchar2(in2, x, y));
+            int2 d = convert_int2(abs(pref - ptst));
+            int e = 0;
+            e = max(e, d.x);
+            e = max(e, d.y);
+            if (e > gAllowedIntError) {
+                errorLoc.x = x;
+                errorLoc.y = y;
+                hadError = true;
+                return false;
+            }
+            merr = max(e, merr);
+        }
+    }
+    return true;
+}
+
+static bool verify_uchar(rs_allocation in1, rs_allocation in2)
+{
+    int merr = 0;
+    uint32_t w = rsAllocationGetDimX(in1);
+    uint32_t h = rsAllocationGetDimY(in1);
+    for (uint32_t y=0; y < h; y++) {
+        for (uint32_t x=0; x < w; x++) {
+            int pref = rsGetElementAt_uchar(in1, x, y);
+            int ptst = rsGetElementAt_uchar(in2, x, y);
+            int e = abs(pref - ptst);
+            if (e > gAllowedIntError) {
+                errorLoc.x = x;
+                errorLoc.y = y;
+                hadError = true;
+                return false;
+            }
+            merr = max(e, merr);
+        }
+    }
+    return true;
+}
+
+#define printCell(txt, a, xy) \
+{                       \
+    rs_element e = rsAllocationGetElement(a); \
+    rs_data_type dt = rsElementGetDataType(e); \
+    uint32_t vs = rsElementGetVectorSize(e); \
+ \
+    if (dt == RS_TYPE_UNSIGNED_8) { \
+        switch(vs) { \
+        case 4: \
+            rsDebug(txt, rsGetElementAt_uchar4(a, xy.x, xy.y)); \
+            break; \
+        case 3: \
+            rsDebug(txt, rsGetElementAt_uchar3(a, xy.x, xy.y)); \
+            break; \
+        case 2: \
+            rsDebug(txt, rsGetElementAt_uchar2(a, xy.x, xy.y)); \
+            break; \
+        case 1: \
+            rsDebug(txt, rsGetElementAt_uchar(a, xy.x, xy.y)); \
+            break; \
+        } \
+    } else { \
+        switch(vs) { \
+        case 4: \
+            rsDebug(txt, rsGetElementAt_float4(a, xy.x, xy.y)); \
+            break; \
+        case 3: \
+            rsDebug(txt, rsGetElementAt_float3(a, xy.x, xy.y)); \
+            break; \
+        case 2: \
+            rsDebug(txt, rsGetElementAt_float2(a, xy.x, xy.y)); \
+            break; \
+        case 1: \
+            rsDebug(txt, rsGetElementAt_float(a, xy.x, xy.y)); \
+            break; \
+        } \
+    } \
+}
+
+void verify(rs_allocation ref_in, rs_allocation tst_in, rs_allocation src_in)
+{
+    rs_element e = rsAllocationGetElement(ref_in);
+    rs_data_type dt = rsElementGetDataType(e);
+    uint32_t vs = rsElementGetVectorSize(e);
+    bool valid = false;
+
+    if (dt == RS_TYPE_UNSIGNED_8) {
+        switch(vs) {
+        case 4:
+            valid = verify_uchar4(ref_in, tst_in);
+            break;
+        case 3:
+            valid = verify_uchar3(ref_in, tst_in);
+            break;
+        case 2:
+            valid = verify_uchar2(ref_in, tst_in);
+            break;
+        case 1:
+            valid = verify_uchar(ref_in, tst_in);
+            break;
+        }
+    } else {
+        switch(vs) {
+        case 4:
+            valid = verify_float4(ref_in, tst_in);
+            break;
+        case 3:
+            valid = verify_float3(ref_in, tst_in);
+            break;
+        case 2:
+            valid = verify_float2(ref_in, tst_in);
+            break;
+        case 1:
+            valid = verify_float(ref_in, tst_in);
+            break;
+        }
+    }
+    if (!valid) {
+        rsDebug("verify failure at xy", errorLoc);
+        printCell("start value     ", src_in, errorLoc);
+        printCell("reference value ", ref_in, errorLoc);
+        printCell("test value      ", tst_in, errorLoc);
+    }
+}
+
+void checkError()
+{
+    if (hadError) {
+        rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+    } else {
+        rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+    }
+}
diff --git a/tests/tests/security/jni/Android.mk b/tests/tests/security/jni/Android.mk
index fa862c1..46d0868 100644
--- a/tests/tests/security/jni/Android.mk
+++ b/tests/tests/security/jni/Android.mk
@@ -31,7 +31,8 @@
 		android_security_cts_SeccompDeathTestService.cpp \
 		android_security_cts_SELinuxTest.cpp \
 		android_security_cts_MMapExecutableTest.cpp \
-		android_security_cts_NetlinkSocket.cpp
+		android_security_cts_NetlinkSocket.cpp \
+		android_security_cts_AudioPolicyBinderTest.cpp
 
 LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
 
diff --git a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
index 0e91b4e..ca8e841 100644
--- a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
+++ b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
@@ -26,6 +26,7 @@
 extern int register_android_security_cts_SeccompDeathTestService(JNIEnv*);
 extern int register_android_security_cts_SELinuxTest(JNIEnv*);
 extern int register_android_security_cts_MMapExecutableTest(JNIEnv* env);
+extern int register_android_security_cts_AudioPolicyBinderTest(JNIEnv* env);
 
 jint JNI_OnLoad(JavaVM *vm, void *reserved) {
     JNIEnv *env = NULL;
@@ -70,5 +71,9 @@
         return JNI_ERR;
     }
 
+    if (register_android_security_cts_AudioPolicyBinderTest(env)) {
+        return JNI_ERR;
+    }
+
     return JNI_VERSION_1_4;
 }
diff --git a/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp b/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp
new file mode 100644
index 0000000..9daa2cb
--- /dev/null
+++ b/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp
@@ -0,0 +1,170 @@
+/*
+ * 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 <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 = 0;
+    }
+    if (session != NULL) {
+        *session = 0;
+    }
+
+    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 = 0; stream < AUDIO_STREAM_CNT; stream++) {
+            *output = AudioSystem::getOutput((audio_stream_type_t)stream);
+            if (*output != 0) {
+                break;
+            }
+        }
+        if (*output == 0) {
+            ALOGE("cannot get valid audio output");
+            return false;
+        }
+    }
+    if (session != NULL) {
+        *session = 10000;
+    }
+    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)(-1), session);
+    if (status == NO_ERROR) {
+        return false;
+    }
+    status = aps->startOutput(output, (audio_stream_type_t)AUDIO_STREAM_CNT, 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)(-1), session);
+    if (status == NO_ERROR) {
+        return false;
+    }
+    status = aps->stopOutput(output, (audio_stream_type_t)AUDIO_STREAM_CNT, 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;
+    }
+
+    status_t status = aps->isStreamActive((audio_stream_type_t)(-1), 0);
+    if (status == NO_ERROR) {
+        return false;
+    }
+    status = aps->isStreamActive((audio_stream_type_t)AUDIO_STREAM_CNT, 0);
+    if (status == NO_ERROR) {
+        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 },
+};
+
+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/src/android/security/cts/AudioPolicyBinderTest.java b/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java
new file mode 100644
index 0000000..399d8bb
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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());
+    }
+
+    private static native boolean native_test_startOutput();
+    private static native boolean native_test_stopOutput();
+    private static native boolean native_test_isStreamActive();
+}
diff --git a/tests/tests/security/src/android/security/cts/SELinuxDomainTest.java b/tests/tests/security/src/android/security/cts/SELinuxDomainTest.java
index 225c623..ee1b027 100644
--- a/tests/tests/security/src/android/security/cts/SELinuxDomainTest.java
+++ b/tests/tests/security/src/android/security/cts/SELinuxDomainTest.java
@@ -337,39 +337,50 @@
                     continue;
                 }
 
-                // Get the context via attr/current
-                String context = new Scanner(new File(f, "attr/current")).next();
-                context = context.trim();
-
-                // Get the vSize, item #23 from the stat file
-                String x = new Scanner(new File(f, "stat")).nextLine();
-                long vSize = getVsizeFromStat(x);
-
-                StringBuilder sb = new StringBuilder();
-                Scanner tmp = new Scanner(new File(f, "cmdline"));
-
-                // Java's scanner tends to return oddly when handling
-                // long binary blobs. Probably some caching optimization.
-                while (tmp.hasNext()) {
-                    sb.append(tmp.next().replace('\0', ' '));
+                try {
+                    ProcessDetails p = getProcessDetails(pid, f);
+                    ArrayList<ProcessDetails> l = map.get(p.label);
+                    if (l == null) {
+                        l = new ArrayList<ProcessDetails>();
+                        map.put(p.label, l);
+                    }
+                    l.add(p);
+                } catch (FileNotFoundException e) {
+                    // sometimes processes go away while the test is running.
+                    // Don't freak out if this happens
                 }
-
-                // At this point we build up a valid proctitle, then split
-                // on whitespace to get the left portion. Which is either
-                // package name or process executable path. This avoids
-                // the comm 16 char width limitation and is limited to PAGE_SIZE
-                String cmdline = sb.toString().trim();
-                cmdline = cmdline.split("\\s+")[0];
-
-                ProcessDetails p = new ProcessDetails(cmdline, context, vSize, pid);
-                ArrayList<ProcessDetails> l = map.get(context);
-                if (l == null) {
-                    l = new ArrayList<ProcessDetails>();
-                    map.put(context, l);
-                }
-                l.add(p);
             }
             return map;
         }
+
+        private static ProcessDetails getProcessDetails(int pid, File f) throws FileNotFoundException {
+            // Get the context via attr/current
+            String context = new Scanner(new File(f, "attr/current")).next();
+            context = context.trim();
+
+            // Get the vSize, item #23 from the stat file
+            String x = new Scanner(new File(f, "stat")).nextLine();
+            long vSize = getVsizeFromStat(x);
+
+            StringBuilder sb = new StringBuilder();
+            Scanner tmp = new Scanner(new File(f, "cmdline"));
+
+            // Java's scanner tends to return oddly when handling
+            // long binary blobs. Probably some caching optimization.
+            while (tmp.hasNext()) {
+                sb.append(tmp.next().replace('\0', ' '));
+            }
+            tmp.close();
+
+            // At this point we build up a valid proctitle, then split
+            // on whitespace to get the left portion. Which is either
+            // package name or process executable path. This avoids
+            // the comm 16 char width limitation and is limited to PAGE_SIZE
+            String cmdline = sb.toString().trim();
+            cmdline = cmdline.split("\\s+")[0];
+
+            return new ProcessDetails(cmdline, context, vSize, pid);
+        }
+
     }
 }
diff --git a/tests/tests/tv/src/android/media/tv/cts/BundledTvInputServiceTest.java b/tests/tests/tv/src/android/media/tv/cts/BundledTvInputServiceTest.java
index 4a9e141..f5cc2e1 100644
--- a/tests/tests/tv/src/android/media/tv/cts/BundledTvInputServiceTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/BundledTvInputServiceTest.java
@@ -133,7 +133,13 @@
             return;
         }
         for (final TvInputInfo info : mPassthroughInputList) {
-            mTvView.tune(info.getId(), TvContract.buildChannelUriForPassthroughInput(info.getId()));
+            runTestOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    mTvView.tune(info.getId(),
+                            TvContract.buildChannelUriForPassthroughInput(info.getId()));
+                }
+            });
             mInstrumentation.waitForIdleSync();
             new PollingCheck(TIME_OUT) {
                 @Override
@@ -156,7 +162,13 @@
         for (int i = 0; i < mPassthroughInputList.size() * STRESS_FACTOR; ++i) {
             final TvInputInfo info =
                     mPassthroughInputList.get(random.nextInt(mPassthroughInputList.size()));
-            mTvView.tune(info.getId(), TvContract.buildChannelUriForPassthroughInput(info.getId()));
+            runTestOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    mTvView.tune(info.getId(),
+                            TvContract.buildChannelUriForPassthroughInput(info.getId()));
+                }
+            });
             mInstrumentation.waitForIdleSync();
             if (random.nextBoolean()) {
                 new PollingCheck(TIME_OUT) {
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 6e30421..f0ee277 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
@@ -44,6 +44,10 @@
 public class TvInputServiceTest extends ActivityInstrumentationTestCase2<TvViewStubActivity> {
     /** The maximum time to wait for an operation. */
     private static final long TIME_OUT = 15000L;
+    private static final String mDummyTrackId = "dummyTrackId";
+    private static final TvTrackInfo mDummyTrack =
+            new TvTrackInfo.Builder(TvTrackInfo.TYPE_SUBTITLE, mDummyTrackId)
+            .setLanguage("und").build();
 
     private TvView mTvView;
     private Activity mActivity;
@@ -250,7 +254,9 @@
     public void verifyCallbackTracksChanged() {
         CountingSession session = CountingTvInputService.sSession;
         assertNotNull(session);
-        session.notifyTracksChanged(new ArrayList<TvTrackInfo>());
+        ArrayList<TvTrackInfo> tracks = new ArrayList<>();
+        tracks.add(mDummyTrack);
+        session.notifyTracksChanged(tracks);
         new PollingCheck(TIME_OUT) {
             @Override
             protected boolean check() {
@@ -262,7 +268,7 @@
     public void verifyCallbackTrackSelected() {
         CountingSession session = CountingTvInputService.sSession;
         assertNotNull(session);
-        session.notifyTrackSelected(TvTrackInfo.TYPE_SUBTITLE, null);
+        session.notifyTrackSelected(mDummyTrack.getType(), mDummyTrack.getId());
         new PollingCheck(TIME_OUT) {
             @Override
             protected boolean check() {
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java b/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java
index 8c95194..930dd6a 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvViewTest.java
@@ -224,17 +224,24 @@
 
     private void selectTrackAndVerify(final int type, final TvTrackInfo track,
             List<TvTrackInfo> tracks) {
+        String selectedTrackId = mTvView.getSelectedTrack(type);
         final int previousGeneration = mCallback.getSelectedTrackGeneration(
                 mStubInfo.getId(), type);
         mTvView.selectTrack(type, track == null ? null : track.getId());
-        new PollingCheck(TIME_OUT) {
-            @Override
-            protected boolean check() {
-                return mCallback.getSelectedTrackGeneration(
-                        mStubInfo.getId(), type) > previousGeneration;
-            }
-        }.run();
-        String selectedTrackId = mTvView.getSelectedTrack(type);
+
+        if ((track == null && selectedTrackId != null)
+                || (track != null && !track.getId().equals(selectedTrackId))) {
+            // Check generation change only if we're actually changing track.
+            new PollingCheck(TIME_OUT) {
+                @Override
+                protected boolean check() {
+                    return mCallback.getSelectedTrackGeneration(
+                            mStubInfo.getId(), type) > previousGeneration;
+                }
+            }.run();
+        }
+
+        selectedTrackId = mTvView.getSelectedTrack(type);
         assertEquals(selectedTrackId, track == null ? null : track.getId());
         if (selectedTrackId != null) {
             TvTrackInfo selectedTrack = null;
diff --git a/tests/tests/uirendering/res/drawable-nodpi/black1.png b/tests/tests/uirendering/res/drawable-nodpi/black1.png
new file mode 100644
index 0000000..3487ced
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/black1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/blackitalic1.png b/tests/tests/uirendering/res/drawable-nodpi/blackitalic1.png
new file mode 100644
index 0000000..8fd3b50
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/blackitalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/bold1.png b/tests/tests/uirendering/res/drawable-nodpi/bold1.png
new file mode 100644
index 0000000..199cccc
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/bold1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/bolditalic1.png b/tests/tests/uirendering/res/drawable-nodpi/bolditalic1.png
new file mode 100644
index 0000000..985635e
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/bolditalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/condensed1.png b/tests/tests/uirendering/res/drawable-nodpi/condensed1.png
new file mode 100644
index 0000000..6889a3a
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/condensed1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/condensedbold1.png b/tests/tests/uirendering/res/drawable-nodpi/condensedbold1.png
new file mode 100644
index 0000000..9554dee
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/condensedbold1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/condensedbolditalic1.png b/tests/tests/uirendering/res/drawable-nodpi/condensedbolditalic1.png
new file mode 100644
index 0000000..0483355
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/condensedbolditalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/condenseditalic1.png b/tests/tests/uirendering/res/drawable-nodpi/condenseditalic1.png
new file mode 100644
index 0000000..6584147
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/condenseditalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/condensedlight1.png b/tests/tests/uirendering/res/drawable-nodpi/condensedlight1.png
new file mode 100644
index 0000000..49d01ac
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/condensedlight1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/condensedlightitalic1.png b/tests/tests/uirendering/res/drawable-nodpi/condensedlightitalic1.png
new file mode 100644
index 0000000..6fe4a76
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/condensedlightitalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/hello1.png b/tests/tests/uirendering/res/drawable-nodpi/hello1.png
new file mode 100644
index 0000000..7a4be5a
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/hello1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/italic1.png b/tests/tests/uirendering/res/drawable-nodpi/italic1.png
new file mode 100644
index 0000000..a5f9ef2
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/italic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/light1.png b/tests/tests/uirendering/res/drawable-nodpi/light1.png
new file mode 100644
index 0000000..dfa59da
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/light1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/lightitalic1.png b/tests/tests/uirendering/res/drawable-nodpi/lightitalic1.png
new file mode 100644
index 0000000..283ddc4
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/lightitalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/medium1.png b/tests/tests/uirendering/res/drawable-nodpi/medium1.png
new file mode 100644
index 0000000..e615186
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/medium1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/mediumitalic1.png b/tests/tests/uirendering/res/drawable-nodpi/mediumitalic1.png
new file mode 100644
index 0000000..3e15fc8
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/mediumitalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/thin1.png b/tests/tests/uirendering/res/drawable-nodpi/thin1.png
new file mode 100644
index 0000000..9637262
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/thin1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/thinitalic1.png b/tests/tests/uirendering/res/drawable-nodpi/thinitalic1.png
new file mode 100644
index 0000000..0afbb9a
--- /dev/null
+++ b/tests/tests/uirendering/res/drawable-nodpi/thinitalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
new file mode 100644
index 0000000..e7ed7ac
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
@@ -0,0 +1,223 @@
+/*
+ * 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.uirendering.cts.testclasses;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.uirendering.cts.bitmapcomparers.BitmapComparer;
+import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
+import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
+import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+import android.uirendering.cts.testinfrastructure.CanvasClient;
+
+import com.android.cts.uirendering.R;
+
+public class FontRenderingTests extends ActivityTestBase {
+    // Threshold is barely loose enough for differences between sw and hw renderers
+    static double MSSIM_THRESHOLD = 0.91;
+
+    private final BitmapComparer mFuzzyComparer = new MSSIMComparer(MSSIM_THRESHOLD);
+
+    // Representative characters including some from Unicode 7
+    private final String mTestString1 = "Hamburg \u20bd";
+    private final String mTestString2 = "\u20b9\u0186\u0254\u1e24\u1e43";
+
+    private void fontTestBody(final Typeface typeface, int id) {
+        Bitmap goldenBitmap = BitmapFactory.decodeResource(getActivity().getResources(), id);
+        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(30);
+                        p.setTypeface(typeface);
+                        canvas.drawText(mTestString1, 10, 60, p);
+                        canvas.drawText(mTestString2, 10, 100, p);
+                    }
+                })
+                .runWithVerifier(new GoldenImageVerifier(goldenBitmap, mFuzzyComparer));
+    }
+
+    @SmallTest
+    public void testDefaultFont() {
+        Typeface tf = Typeface.create("sans-serif", Typeface.NORMAL);
+        fontTestBody(tf, R.drawable.hello1);
+    }
+
+    @SmallTest
+    public void testBoldFont() {
+        Typeface tf = Typeface.create("sans-serif", Typeface.BOLD);
+        fontTestBody(tf, R.drawable.bold1);
+    }
+
+    @SmallTest
+    public void testItalicFont() {
+        Typeface tf = Typeface.create("sans-serif", Typeface.ITALIC);
+        fontTestBody(tf, R.drawable.italic1);
+    }
+
+    @SmallTest
+    public void testBoldItalicFont() {
+        Typeface tf = Typeface.create("sans-serif", Typeface.BOLD | Typeface.ITALIC);
+        fontTestBody(tf, R.drawable.bolditalic1);
+    }
+
+    @SmallTest
+    public void testMediumFont() {
+        Typeface tf = Typeface.create("sans-serif-medium", Typeface.NORMAL);
+        fontTestBody(tf, R.drawable.medium1);
+    }
+
+    @SmallTest
+    public void testMediumBoldFont() {
+        // bold attribute on medium base font = black
+        Typeface tf = Typeface.create("sans-serif-medium", Typeface.BOLD);
+        fontTestBody(tf, R.drawable.black1);
+    }
+
+    @SmallTest
+    public void testMediumItalicFont() {
+        Typeface tf = Typeface.create("sans-serif-medium", Typeface.ITALIC);
+        fontTestBody(tf, R.drawable.mediumitalic1);
+    }
+
+    @SmallTest
+    public void testMediumBoldItalicFont() {
+        Typeface tf = Typeface.create("sans-serif-medium", Typeface.BOLD | Typeface.ITALIC);
+        fontTestBody(tf, R.drawable.blackitalic1);
+    }
+
+    @SmallTest
+    public void testLightFont() {
+        Typeface tf = Typeface.create("sans-serif-light", Typeface.NORMAL);
+        fontTestBody(tf, R.drawable.light1);
+    }
+
+    @SmallTest
+    public void testLightBoldFont() {
+        // bold attribute on light base font = medium
+        Typeface tf = Typeface.create("sans-serif-light", Typeface.BOLD);
+        fontTestBody(tf, R.drawable.medium1);
+    }
+
+    @SmallTest
+    public void testLightItalicFont() {
+        Typeface tf = Typeface.create("sans-serif-light", Typeface.ITALIC);
+        fontTestBody(tf, R.drawable.lightitalic1);
+    }
+
+    @SmallTest
+    public void testLightBoldItalicFont() {
+        Typeface tf = Typeface.create("sans-serif-light", Typeface.BOLD | Typeface.ITALIC);
+        fontTestBody(tf, R.drawable.mediumitalic1);
+    }
+
+    @SmallTest
+    public void testThinFont() {
+        Typeface tf = Typeface.create("sans-serif-thin", Typeface.NORMAL);
+        fontTestBody(tf, R.drawable.thin1);
+    }
+
+    @SmallTest
+    public void testThinBoldFont() {
+        // bold attribute on thin base font = normal
+        Typeface tf = Typeface.create("sans-serif-thin", Typeface.BOLD);
+        fontTestBody(tf, R.drawable.hello1);
+    }
+
+    @SmallTest
+    public void testThinItalicFont() {
+        Typeface tf = Typeface.create("sans-serif-thin", Typeface.ITALIC);
+        fontTestBody(tf, R.drawable.thinitalic1);
+    }
+
+    @SmallTest
+    public void testThinBoldItalicFont() {
+        Typeface tf = Typeface.create("sans-serif-thin", Typeface.BOLD | Typeface.ITALIC);
+        fontTestBody(tf, R.drawable.italic1);
+    }
+
+    @SmallTest
+    public void testBlackFont() {
+        Typeface tf = Typeface.create("sans-serif-black", Typeface.NORMAL);
+        fontTestBody(tf, R.drawable.black1);
+    }
+
+    @SmallTest
+    public void testBlackBoldFont() {
+        // bold attribute on black base font = black
+        Typeface tf = Typeface.create("sans-serif-black", Typeface.BOLD);
+        fontTestBody(tf, R.drawable.black1);
+    }
+
+    @SmallTest
+    public void testBlackItalicFont() {
+        Typeface tf = Typeface.create("sans-serif-black", Typeface.ITALIC);
+        fontTestBody(tf, R.drawable.blackitalic1);
+    }
+
+    @SmallTest
+    public void testBlackBoldItalicFont() {
+        Typeface tf = Typeface.create("sans-serif-black", Typeface.BOLD | Typeface.ITALIC);
+        fontTestBody(tf, R.drawable.blackitalic1);
+    }
+
+    /* condensed fonts */
+
+    @SmallTest
+    public void testCondensedFont() {
+        Typeface tf = Typeface.create("sans-serif-condensed", Typeface.NORMAL);
+        fontTestBody(tf, R.drawable.condensed1);
+    }
+
+    @SmallTest
+    public void testCondensedBoldFont() {
+        Typeface tf = Typeface.create("sans-serif-condensed", Typeface.BOLD);
+        fontTestBody(tf, R.drawable.condensedbold1);
+    }
+
+    @SmallTest
+    public void testCondensedItalicFont() {
+        Typeface tf = Typeface.create("sans-serif-condensed", Typeface.ITALIC);
+        fontTestBody(tf, R.drawable.condenseditalic1);
+    }
+
+    @SmallTest
+    public void testCondensedBoldItalicFont() {
+        Typeface tf = Typeface.create("sans-serif-condensed", Typeface.BOLD | Typeface.ITALIC);
+        fontTestBody(tf, R.drawable.condensedbolditalic1);
+    }
+
+    @SmallTest
+    public void testCondensedLightFont() {
+        Typeface tf = Typeface.create("sans-serif-condensed-light", Typeface.NORMAL);
+        fontTestBody(tf, R.drawable.condensedlight1);
+    }
+
+    @SmallTest
+    public void testCondensedLightItalicFont() {
+        Typeface tf = Typeface.create("sans-serif-condensed-light", Typeface.ITALIC);
+        fontTestBody(tf, R.drawable.condensedlightitalic1);
+    }
+}
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 9f9aa41..052b251 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
@@ -185,7 +185,8 @@
                 TEST_WIDTH, TEST_HEIGHT);
         boolean success = bitmapVerifier.verify(mSoftwareArray, 0, TEST_WIDTH, TEST_WIDTH, TEST_HEIGHT);
         if (!success) {
-            BitmapDumper.dumpBitmap(bitmap, getName(), this.getClass().getSimpleName());
+            Bitmap croppedBitmap = Bitmap.createBitmap(bitmap, 0, 0, TEST_WIDTH, TEST_HEIGHT);
+            BitmapDumper.dumpBitmap(croppedBitmap, getName(), this.getClass().getSimpleName());
             BitmapDumper.dumpBitmap(bitmapVerifier.getDifferenceBitmap(), getName() + "_verifier",
                     this.getClass().getSimpleName());
         }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java
index be680d9..41e255b 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java
@@ -84,9 +84,10 @@
         int[] visualizerArray = differenceVisualizer.getDifferences(idealArray, testedArray);
         visualizerBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
         visualizerBitmap.setPixels(visualizerArray, 0, width, 0, 0, width, height);
+        Bitmap croppedBitmap = Bitmap.createBitmap(testedBitmap, 0, 0, width, height);
 
         saveFile(className, testName, IDEAL_RENDERING_FILE_NAME, idealBitmap);
-        saveFile(className, testName, TESTED_RENDERING_FILE_NAME, testedBitmap);
+        saveFile(className, testName, TESTED_RENDERING_FILE_NAME, croppedBitmap);
         saveFile(className, testName, VISUALIZER_RENDERING_FILE_NAME, visualizerBitmap);
     }
 
diff --git a/tests/tests/widget/res/layout/popupwindow.xml b/tests/tests/widget/res/layout/popupwindow.xml
index 2508115..f93f965 100644
--- a/tests/tests/widget/res/layout/popupwindow.xml
+++ b/tests/tests/widget/res/layout/popupwindow.xml
@@ -14,37 +14,36 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:orientation="vertical">
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
 
-    <TextView android:id="@+id/anchor_upper"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="@string/text_view_hint" />
+    <View android:id="@+id/anchor_upper"
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:layout_alignParentTop="true"
+        android:layout_centerHorizontal="true"
+        android:background="#f00" />
 
-    <LinearLayout android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_weight="1">
+    <View android:id="@+id/anchor_lower"
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:layout_alignParentBottom="true"
+        android:layout_centerHorizontal="true"
+        android:background="#0f0" />
 
-        <TextView android:id="@+id/anchor_middle_left"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:text="@string/text_view_hint"
-            android:layout_weight="1"/>
+    <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" />
 
-        <TextView android:id="@+id/anchor_middle_right"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:text="@string/text_view_hint"
-            android:layout_weight="1"/>
+    <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" />
 
-    </LinearLayout>
-
-    <TextView android:id="@+id/anchor_lower"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="@string/text_view_hint" />
-
-</LinearLayout>
+</RelativeLayout>
diff --git a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
index 4a14d2b..e1742c8 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
@@ -25,6 +25,7 @@
 import android.graphics.Color;
 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;
@@ -580,7 +581,8 @@
         assertEquals(50, mPopupWindow.getHeight());
 
         mPopupWindow.getContentView().getLocationOnScreen(viewXY);
-        // the position should be changed
+
+        // The popup should appear below and to right with an offset.
         assertEquals(anchorXY[0] + 20 + viewInWindowOff[0], viewXY[0]);
         assertEquals(anchorXY[1] + anchorView.getHeight() + 50 + viewInWindowOff[1], viewXY[1]);
 
@@ -597,14 +599,15 @@
         assertEquals(50, mPopupWindow.getHeight());
 
         mPopupWindow.getContentView().getLocationOnScreen(viewXY);
-        // the position should be changed
+
+        // The popup should appear below and to right with an offset.
         assertEquals(anchorXY[0] + 10 + viewInWindowOff[0], viewXY[0]);
         assertEquals(anchorXY[1] + anchorView.getHeight() + 50 + viewInWindowOff[1], viewXY[1]);
 
-        final View anthoterView = mActivity.findViewById(R.id.anchor_middle_right);
+        final View anotherView = mActivity.findViewById(R.id.anchor_middle_left);
         mInstrumentation.runOnMainSync(new Runnable() {
             public void run() {
-                mPopupWindow.update(anthoterView, 0, 0, 60, 60);
+                mPopupWindow.update(anotherView, 0, 0, 60, 60);
             }
         });
         mInstrumentation.waitForIdleSync();
@@ -614,11 +617,12 @@
         assertEquals(60, mPopupWindow.getHeight());
 
         int[] newXY = new int[2];
-        anthoterView.getLocationOnScreen(newXY);
+        anotherView.getLocationOnScreen(newXY);
         mPopupWindow.getContentView().getLocationOnScreen(viewXY);
-        // the position should be changed
+
+        // The popup should appear below and to the right.
         assertEquals(newXY[0] + viewInWindowOff[0], viewXY[0]);
-        assertEquals(newXY[1] + anthoterView.getHeight() + viewInWindowOff[1], viewXY[1]);
+        assertEquals(newXY[1] + anotherView.getHeight() + viewInWindowOff[1], viewXY[1]);
 
         dismissPopup();
     }
@@ -815,8 +819,7 @@
     }
 
     private View createPopupContent() {
-        TextView popupView = new TextView(mActivity);
-        popupView.setText("Popup");
+        View popupView = new View(mActivity);
         popupView.setLayoutParams(new ViewGroup.LayoutParams(50, 50));
         popupView.setBackgroundColor(Color.WHITE);
 
diff --git a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java
index 1680cae..833bf69 100644
--- a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java
+++ b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java
@@ -205,7 +205,8 @@
             String className = nameCollector.toString();
             nameCollector.append('#').append(test.getName());
             writer.append("<Test name=\"").append(test.getName()).append("\"");
-            String abis = getSupportedAbis(mUnsupportedAbis, mArchitecture, className).toString();
+            String abis = getSupportedAbis(mUnsupportedAbis, mArchitecture,
+                    className, nameCollector.toString()).toString();
             writer.append(" abis=\"" + abis.substring(1, abis.length() - 1) + "\"");
             if (isKnownFailure(mKnownFailures, nameCollector.toString())) {
                 writer.append(" expectation=\"failure\"");
@@ -232,23 +233,36 @@
 
     // Returns the list of ABIs supported by this TestCase on this architecture.
     public static Set<String> getSupportedAbis(ExpectationStore expectationStore,
-            String architecture, String className) {
+            String architecture, String className, String testName) {
         Set<String> supportedAbis = AbiUtils.getAbisForArch(architecture);
-        Expectation e = (expectationStore == null) ? null : expectationStore.get(className);
-        if (e != null && !e.getDescription().isEmpty()) {
-            // Description should be written in the form "blah blah: abi1, abi2..."
-            String description = e.getDescription().split(":")[1];
-            String[] unsupportedAbis = description.split(",");
-            for (String a : unsupportedAbis) {
-                String abi = a.trim();
-                if (!AbiUtils.isAbiSupportedByCts(abi)) {
-                    throw new RuntimeException(
-                            String.format("Unrecognised ABI %s in %s", abi, e.getDescription()));
-                }
-                supportedAbis.remove(abi);
-            }
+        if (expectationStore == null) {
+            return supportedAbis;
         }
+
+        removeUnsupportedAbis(expectationStore.get(className), supportedAbis);
+        removeUnsupportedAbis(expectationStore.get(testName), supportedAbis);
         return supportedAbis;
     }
 
+    public static void removeUnsupportedAbis(Expectation expectation, Set<String> supportedAbis) {
+        if (expectation == null) {
+            return;
+        }
+
+        String description = expectation.getDescription();
+        if (description.isEmpty()) {
+            return;
+        }
+
+        String[] unsupportedAbis = description.split(":")[1].split(",");
+        for (String a : unsupportedAbis) {
+            String abi = a.trim();
+            if (!AbiUtils.isAbiSupportedByCts(abi)) {
+                throw new RuntimeException(
+                        String.format("Unrecognised ABI %s in %s", abi, description));
+            }
+            supportedAbis.remove(abi);
+        }
+    }
+
 }
diff --git a/tools/tradefed-host/etc/cts-tradefed b/tools/tradefed-host/etc/cts-tradefed
index f9f43bb..9a643de 100755
--- a/tools/tradefed-host/etc/cts-tradefed
+++ b/tools/tradefed-host/etc/cts-tradefed
@@ -35,7 +35,7 @@
 checkPath java
 
 # check java version
-JAVA_VERSION=$(java -version 2>&1 | head -n 1 | grep '[ "]1\.[67][\. "$$]')
+JAVA_VERSION=$(java -version 2>&1 | head -n 2 | grep '[ "]1\.[67][\. "$$]')
 if [ "${JAVA_VERSION}" == "" ]; then
     echo "Wrong java version. 1.6 or 1.7 is required."
     exit
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildHelper.java b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildHelper.java
index 61b4b43..0940355 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildHelper.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildHelper.java
@@ -33,7 +33,7 @@
     private final String mSuiteName = "CTS";
     /** The root location of the extracted CTS package */
     private final File mRootDir;
-    /** the {@link CTS_DIR_NAME} directory */
+    /** the {@link #CTS_DIR_NAME} directory */
     private final File mCtsDir;
 
     /**
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
index 27f9135..25431b2 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
@@ -31,7 +31,7 @@
     @Option(name="cts-install-path", description="the path to the cts installation to use")
     private String mCtsRootDirPath = System.getProperty("CTS_ROOT");
 
-    public static final String CTS_BUILD_VERSION = "5.0_r0.5";
+    public static final String CTS_BUILD_VERSION = "5.0_r2";
 
     /**
      * {@inheritDoc}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/command/CtsConsole.java b/tools/tradefed-host/src/com/android/cts/tradefed/command/CtsConsole.java
index 7333de2..ca4e050 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/command/CtsConsole.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/command/CtsConsole.java
@@ -80,7 +80,7 @@
             public void run() {
                 CtsBuildHelper ctsBuild = getCtsBuild();
                 if (ctsBuild != null) {
-                    listPackages(ctsBuild, AbiUtils.getAbisSupportedByCts());
+                    listPackages(ctsBuild);
                 }
             }
         }, LIST_PATTERN, "packages");
@@ -193,8 +193,8 @@
         }
     }
 
-    private void listPackages(CtsBuildHelper ctsBuild, Set<String> abis) {
-        ITestPackageRepo testCaseRepo = new TestPackageRepo(ctsBuild.getTestCasesDir(), abis, false);
+    private void listPackages(CtsBuildHelper ctsBuild) {
+        ITestPackageRepo testCaseRepo = new TestPackageRepo(ctsBuild.getTestCasesDir(), false);
         for (String packageName : testCaseRepo.getPackageNames()) {
             printLine(packageName);
         }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
index e8d6e71..8cb4072 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
@@ -27,13 +27,15 @@
 import com.android.tradefed.config.Option;
 import com.android.tradefed.config.Option.Importance;
 import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.ILogSaver;
+import com.android.tradefed.result.ILogSaverListener;
 import com.android.tradefed.result.ITestInvocationListener;
 import com.android.tradefed.result.ITestSummaryListener;
 import com.android.tradefed.result.InputStreamSource;
 import com.android.tradefed.result.LogDataType;
+import com.android.tradefed.result.LogFile;
 import com.android.tradefed.result.LogFileSaver;
 import com.android.tradefed.result.TestSummary;
-import com.android.tradefed.util.AbiFormatter;
 import com.android.tradefed.util.FileUtil;
 import com.android.tradefed.util.StreamUtil;
 
@@ -55,7 +57,9 @@
  * <p/>
  * Outputs xml in format governed by the cts_result.xsd
  */
-public class CtsXmlResultReporter implements ITestInvocationListener, ITestSummaryListener {
+public class CtsXmlResultReporter
+        implements ITestInvocationListener, ITestSummaryListener, ILogSaverListener {
+
     private static final String LOG_TAG = "CtsXmlResultReporter";
 
     static final String TEST_RESULT_FILE_NAME = "testResult.xml";
@@ -90,11 +94,15 @@
     @Option(name = "result-server", description = "Server to publish test results.")
     private String mResultServer;
 
+    @Option(name = "include-test-log-tags", description = "Include test log tags in XML report.")
+    private boolean mIncludeTestLogTags = false;
+
     protected IBuildInfo mBuildInfo;
     private String mStartTime;
     private String mDeviceSerial;
     private TestResults mResults = new TestResults();
     private TestPackageResult mCurrentPkgResult = null;
+    private Test mCurrentTest = null;
     private boolean mIsDeviceInfoRun = false;
     private ResultReporter mReporter;
     private File mLogDir;
@@ -105,6 +113,11 @@
         mReportDir = reportDir;
     }
 
+    /** Set whether to include TestLog tags in the XML reports. */
+    public void setIncludeTestLogTags(boolean include) {
+        mIncludeTestLogTags = include;
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -212,6 +225,20 @@
     }
 
     /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void testLogSaved(String dataName, LogDataType dataType, InputStreamSource dataStream,
+            LogFile logFile) {
+        if (mIncludeTestLogTags && mCurrentTest != null) {
+            TestLog log = TestLog.fromDataName(dataName, logFile.getUrl());
+            if (log != null) {
+                mCurrentTest.addTestLog(log);
+            }
+        }
+    }
+
+    /**
      * Return the {@link LogFileSaver} to use.
      * <p/>
      * Exposed for unit testing.
@@ -220,11 +247,18 @@
         return new LogFileSaver(mLogDir);
     }
 
+    @Override
+    public void setLogSaver(ILogSaver logSaver) {
+      // Don't need to keep a reference to logSaver, because we don't save extra logs in this class.
+    }
 
     @Override
     public void testRunStarted(String id, int numTests) {
-        mCurrentPkgResult = mResults.getOrCreatePackage(id);
         mIsDeviceInfoRun = DeviceInfoCollector.IDS.contains(id);
+        if (!mIsDeviceInfoRun) {
+            mCurrentPkgResult = mResults.getOrCreatePackage(id);
+            mCurrentPkgResult.setDeviceSerial(mDeviceSerial);
+        }
     }
 
     /**
@@ -232,7 +266,9 @@
      */
     @Override
     public void testStarted(TestIdentifier test) {
-        mCurrentPkgResult.insertTest(test);
+        if (!mIsDeviceInfoRun) {
+            mCurrentTest = mCurrentPkgResult.insertTest(test);
+        }
     }
 
     /**
@@ -240,7 +276,9 @@
      */
     @Override
     public void testFailed(TestIdentifier test, String trace) {
-        mCurrentPkgResult.reportTestFailure(test, CtsTestStatus.FAIL, trace);
+        if (!mIsDeviceInfoRun) {
+            mCurrentPkgResult.reportTestFailure(test, CtsTestStatus.FAIL, trace);
+        }
     }
 
     /**
@@ -249,7 +287,9 @@
     @Override
     public void testAssumptionFailure(TestIdentifier test, String trace) {
         // TODO: do something different here?
-        mCurrentPkgResult.reportTestFailure(test, CtsTestStatus.FAIL, trace);
+        if (!mIsDeviceInfoRun) {
+            mCurrentPkgResult.reportTestFailure(test, CtsTestStatus.FAIL, trace);
+        }
     }
 
     /**
@@ -265,7 +305,9 @@
      */
     @Override
     public void testEnded(TestIdentifier test, Map<String, String> testMetrics) {
-        mCurrentPkgResult.reportTestEnded(test, testMetrics);
+        if (!mIsDeviceInfoRun) {
+            mCurrentPkgResult.reportTestEnded(test, testMetrics);
+        }
     }
 
     /**
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/PlanCreator.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/PlanCreator.java
index 713e8fa..3881c0e 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/PlanCreator.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/PlanCreator.java
@@ -116,8 +116,8 @@
     public ITestPlan createDerivedPlan(CtsBuildHelper build, Set<String> abis)
             throws ConfigurationException {
         checkFields(build);
-        ITestPackageRepo pkgDefRepo = new TestPackageRepo(build.getTestCasesDir(),
-                abis, mIncludeKnownFailures);
+        ITestPackageRepo pkgDefRepo =
+                new TestPackageRepo(build.getTestCasesDir(), mIncludeKnownFailures);
         ITestPlan derivedPlan = new TestPlan(mPlanName, abis);
         for (TestPackageResult pkg : mResult.getPackages()) {
             Collection<TestIdentifier> filteredTests = pkg.getTestsWithStatus(mResultFilter);
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/Test.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/Test.java
index 023cfcb..12a2b29 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/Test.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/Test.java
@@ -16,12 +16,15 @@
 package com.android.cts.tradefed.result;
 
 import com.android.ddmlib.Log;
+import com.android.cts.tradefed.result.TestLog.TestLogType;
 
 import org.kxml2.io.KXmlSerializer;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Data structure that represents a "Test" result XML element.
@@ -58,6 +61,12 @@
     private String mDetails;
 
     /**
+     * Log info for this test like a logcat dump or bugreport.
+     * Use *Locked methods instead of mutating this directly.
+     */
+    private List<TestLog> mTestLogs;
+
+    /**
      * Create an empty {@link Test}
      */
     public Test() {
@@ -76,6 +85,13 @@
     }
 
     /**
+     * Add a test log to this Test.
+     */
+    public void addTestLog(TestLog testLog) {
+        addTestLogLocked(testLog);
+    }
+
+    /**
      * Set the name of this {@link Test}
      */
     public void setName(String name) {
@@ -157,6 +173,8 @@
         serializer.attribute(CtsXmlResultReporter.ns, STARTTIME_ATTR, mStartTime);
         serializer.attribute(CtsXmlResultReporter.ns, ENDTIME_ATTR, mEndTime);
 
+        serializeTestLogsLocked(serializer);
+
         if (mMessage != null) {
             serializer.startTag(CtsXmlResultReporter.ns, SCENE_TAG);
             serializer.attribute(CtsXmlResultReporter.ns, MESSAGE_ATTR, mMessage);
@@ -328,10 +346,38 @@
                 mMessage = getAttribute(parser, MESSAGE_ATTR);
             } else if (eventType == XmlPullParser.START_TAG && parser.getName().equals(STACK_TAG)) {
                 mStackTrace = parser.nextText();
+            } else if (eventType == XmlPullParser.START_TAG && TestLog.isTag(parser.getName())) {
+                parseTestLog(parser);
             } else if (eventType == XmlPullParser.END_TAG && parser.getName().equals(TAG)) {
                 return;
             }
             eventType = parser.next();
         }
     }
+
+    /** Parse a TestLog entry from the parser positioned at a TestLog tag. */
+    private void parseTestLog(XmlPullParser parser) throws XmlPullParserException{
+        TestLog log = TestLog.fromXml(parser);
+        if (log == null) {
+            throw new XmlPullParserException("invalid XML: bad test log tag");
+        }
+        addTestLog(log);
+    }
+
+    /** Add a TestLog to the test in a thread safe manner. */
+    private synchronized void addTestLogLocked(TestLog testLog) {
+        if (mTestLogs == null) {
+            mTestLogs = new ArrayList<>(TestLogType.values().length);
+        }
+        mTestLogs.add(testLog);
+    }
+
+    /** Serialize the TestLogs of this test in a thread safe manner. */
+    private synchronized void serializeTestLogsLocked(KXmlSerializer serializer) throws IOException {
+        if (mTestLogs != null) {
+            for (TestLog log : mTestLogs) {
+                log.serialize(serializer);
+            }
+        }
+    }
 }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/TestLog.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/TestLog.java
new file mode 100644
index 0000000..1210432
--- /dev/null
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/TestLog.java
@@ -0,0 +1,148 @@
+/*
+ * 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 com.android.cts.tradefed.result;
+
+import org.kxml2.io.KXmlSerializer;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.io.IOException;
+
+import javax.annotation.Nullable;
+
+/**
+ * TestLog describes a log for a test. It corresponds to the "TestLog" XML element.
+ */
+class TestLog {
+
+    private static final String TAG = "TestLog";
+    private static final String TYPE_ATTR = "type";
+    private static final String URL_ATTR = "url";
+
+    /** Type of log. */
+    public enum TestLogType {
+        LOGCAT("logcat-"),
+        BUGREPORT("bug-"),
+
+        ;
+
+        // This enum restricts the type of logs reported back to the server,
+        // because we do not intend to support them all. Using an enum somewhat
+        // assures that we will only see these expected types on the server side.
+
+        /**
+         * Returns the TestLogType from an ILogSaver data name or null
+         * if the data name is not supported.
+         */
+        @Nullable
+        static TestLogType fromDataName(String dataName) {
+            if (dataName == null) {
+                return null;
+            }
+
+            for (TestLogType type : values()) {
+                if (dataName.startsWith(type.dataNamePrefix)) {
+                    return type;
+                }
+            }
+            return null;
+        }
+
+        private final String dataNamePrefix;
+
+        private TestLogType(String dataNamePrefix) {
+            this.dataNamePrefix = dataNamePrefix;
+        }
+
+        String getAttrValue() {
+            return name().toLowerCase();
+        }
+    }
+
+    /** Type of the log like LOGCAT or BUGREPORT. */
+    private final TestLogType mLogType;
+
+    /** Url pointing to the log file. */
+    private final String mUrl;
+
+    /** Create a TestLog from an ILogSaver callback. */
+    @Nullable
+    static TestLog fromDataName(String dataName, String url) {
+        TestLogType logType = TestLogType.fromDataName(dataName);
+        if (logType == null) {
+            return null;
+        }
+
+        if (url == null) {
+            return null;
+        }
+
+        return new TestLog(logType, url);
+    }
+
+    /** Create a TestLog from XML given a XmlPullParser positioned at the TestLog tag. */
+    @Nullable
+    static TestLog fromXml(XmlPullParser parser) {
+        String type = parser.getAttributeValue(null, TYPE_ATTR);
+        if (type == null) {
+            return null;
+        }
+
+        String url = parser.getAttributeValue(null, URL_ATTR);
+        if (url == null) {
+            return null;
+        }
+
+        try {
+            TestLogType logType = TestLogType.valueOf(type.toUpperCase());
+            return new TestLog(logType, url);
+        } catch (IllegalArgumentException e) {
+            return null;
+        }
+    }
+
+    /** Create a TestLog directly given a log type and url. */
+    public static TestLog of(TestLogType logType, String url) {
+        return new TestLog(logType, url);
+    }
+
+    private TestLog(TestLogType logType, String url) {
+        this.mLogType = logType;
+        this.mUrl = url;
+    }
+
+    /** Returns this TestLog's log type. */
+    TestLogType getLogType() {
+        return mLogType;
+    }
+
+    /** Returns this TestLog's URL. */
+    String getUrl() {
+        return mUrl;
+    }
+
+    /** Serialize the TestLog to XML. */
+    public void serialize(KXmlSerializer serializer) throws IOException {
+        serializer.startTag(CtsXmlResultReporter.ns, TAG);
+        serializer.attribute(CtsXmlResultReporter.ns, TYPE_ATTR, mLogType.getAttrValue());
+        serializer.attribute(CtsXmlResultReporter.ns, URL_ATTR, mUrl);
+        serializer.endTag(CtsXmlResultReporter.ns, TAG);
+    }
+
+    /** Returns true if the tag is a TestLog tag. */
+    public static boolean isTag(String tagName) {
+        return TAG.equals(tagName);
+    }
+}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
index 6d617ea..ce48664 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
@@ -37,6 +37,7 @@
 import com.android.tradefed.result.InputStreamSource;
 import com.android.tradefed.result.LogDataType;
 import com.android.tradefed.result.ResultForwarder;
+import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IBuildReceiver;
 import com.android.tradefed.testtype.IDeviceTest;
 import com.android.tradefed.testtype.IRemoteTest;
@@ -56,13 +57,13 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.Queue;
 import java.util.Set;
 
 
@@ -86,8 +87,6 @@
     public static final String PACKAGE_ABI_METRIC = "packageAbi";
     public static final String PACKAGE_DIGEST_METRIC = "packageDigest";
 
-    private ITestDevice mDevice;
-
     @Option(name = PLAN_OPTION, description = "the test plan to run.",
             importance = Importance.IF_UNSET)
     private String mPlanName = null;
@@ -181,19 +180,34 @@
             "Collect dEQP logs from the device.")
     private boolean mCollectDeqpLogs = false;
 
-    private long mPrevRebootTime; // last reboot time
+    @Option(name = "min-pre-reboot-package-count", description =
+            "The minimum number of packages to require a pre test reboot")
+
+    private int mMinPreRebootPackageCount = 2;
+    private final int mShardAssignment;
+    private final int mTotalShards;
+    private ITestDevice mDevice = null;
+    private CtsBuildHelper mCtsBuild = null;
+    private IBuildInfo mBuildInfo = null;
+    // last reboot time
+    private long mPrevRebootTime;
+    // The list of packages to run. populated in {@code setupTestPackageList}
+    // This is a member variable so that run can be called more than once
+    // and the test run is resumed.
+    private List<TestPackage> mTestPackageList = new ArrayList<>();
+    // The index in the pacakge list of the last test to complete
+    private int mLastTestPackageIndex = 0;
 
     /** data structure for a {@link IRemoteTest} and its known tests */
-    class TestPackage {
+    static class TestPackage {
         private final IRemoteTest mTestForPackage;
         private final ITestPackageDef mPackageDef;
         private final Collection<TestIdentifier> mKnownTests;
 
-        TestPackage(ITestPackageDef packageDef, IRemoteTest testForPackage,
-                Collection<TestIdentifier> knownTests) {
+        TestPackage(ITestPackageDef packageDef, IRemoteTest testForPackage) {
             mPackageDef = packageDef;
             mTestForPackage = testForPackage;
-            mKnownTests = knownTests;
+            mKnownTests = packageDef.getTests();
         }
 
         IRemoteTest getTestForPackage() {
@@ -209,11 +223,18 @@
         }
 
         /**
-         * Return the test run name that should be used for the TestPackage
+         * @return the test run name that should be used for the TestPackage.
          */
         String getTestRunName() {
             return mPackageDef.getId();
         }
+
+        /**
+         * @return the ABI on which the test will run.
+         */
+        IAbi getAbi() {
+            return mPackageDef.getAbi();
+        }
     }
 
     /**
@@ -293,11 +314,28 @@
         }
     }
 
-    /** list of remaining tests to execute */
-    private List<TestPackage> mRemainingTestPkgs = null;
+    /**
+     * Create a new {@link CtsTest} that will run the default list of {@link TestPackage}s.
+     */
+    public CtsTest() {
+        this(0 /*shardAssignment*/, 1 /*totalShards*/);
+    }
 
-    private CtsBuildHelper mCtsBuild = null;
-    private IBuildInfo mBuildInfo = null;
+    /**
+     * Create a new {@link CtsTest} that will run the given {@link List} of {@link TestPackage}s.
+     */
+    public CtsTest(int shardAssignment, int totalShards) {
+        if (shardAssignment < 0) {
+            throw new IllegalArgumentException(
+                "shardAssignment cannot be negative. found:" + shardAssignment);
+        }
+        if (totalShards < 1) {
+            throw new IllegalArgumentException(
+                "shardAssignment must be at least 1. found:" + totalShards);
+        }
+        this.mShardAssignment = shardAssignment;
+        this.mTotalShards = totalShards;
+    }
 
     /**
      * {@inheritDoc}
@@ -408,8 +446,6 @@
      * Set the CTS build container.
      * <p/>
      * Exposed so unit tests can mock the provided build.
-     *
-     * @param buildHelper
      */
     void setBuildHelper(CtsBuildHelper buildHelper) {
         mCtsBuild = buildHelper;
@@ -424,50 +460,62 @@
             throw new IllegalArgumentException("missing device");
         }
 
-        if (mRemainingTestPkgs == null) {
-            checkFields();
-            mRemainingTestPkgs = buildTestsToRun();
+        Set<String> abiSet = getAbis();
+        if (abiSet == null || abiSet.isEmpty()) {
+            throw new IllegalArgumentException("could not get device's ABIs");
         }
+        Log.logAndDisplay(LogLevel.INFO, LOG_TAG, "ABIs: " + abiSet);
+
+        checkFields();
+        setupTestPackageList(abiSet);
         if (mBugreport) {
-            FailedTestBugreportGenerator bugListener = new FailedTestBugreportGenerator(listener,
-                    getDevice());
-            listener = bugListener;
+            listener = new FailedTestBugreportGenerator(listener, getDevice());
         }
         if (mScreenshotOnFailures) {
-            FailedTestScreenshotGenerator screenListener = new FailedTestScreenshotGenerator(
-                    listener, getDevice());
-            listener = screenListener;
+            listener = new FailedTestScreenshotGenerator(listener, getDevice());
         }
         if (mLogcatOnFailures) {
-            FailedTestLogcatGenerator logcatListener = new FailedTestLogcatGenerator(
-                    listener, getDevice(), mMaxLogcatBytes);
-            listener = logcatListener;
+            listener = new FailedTestLogcatGenerator(listener, getDevice(), mMaxLogcatBytes);
+        }
+
+        // Setup the a map of Test id to ResultFilter
+        Map<String, ResultFilter> filterMap = new HashMap<>();
+        int totalTestCount = 0;
+        for (TestPackage testPackage : mTestPackageList) {
+            ResultFilter resultFilter = new ResultFilter(listener, testPackage);
+            totalTestCount += resultFilter.getKnownTestCount();
+            filterMap.put(testPackage.getPackageDef().getId(), resultFilter);
         }
 
         // collect and install the prerequisiteApks first, to save time when multiple test
-        // packages are using the same prerequisite apk (I'm looking at you, CtsTestStubs!)
-        Collection<String> prerequisiteApks = getPrerequisiteApks(mRemainingTestPkgs);
-        Collection<String> uninstallPackages = getPrerequisitePackageNames(mRemainingTestPkgs);
-        List<ResultFilter> filters = new ArrayList<ResultFilter>(mRemainingTestPkgs.size());
+        // packages are using the same prerequisite apk
+        Map<String, Set<String>> prerequisiteApks = getPrerequisiteApks(mTestPackageList, abiSet);
+        Collection<String> uninstallPackages = getPrerequisitePackageNames(mTestPackageList);
 
         try {
-            installPrerequisiteApks(prerequisiteApks);
-
             // always collect the device info, even for resumed runs, since test will likely be
             // running on a different device
             collectDeviceInfo(getDevice(), mCtsBuild, listener);
-            if (mRemainingTestPkgs.size() > 1 && !mDisableReboot) {
-                Log.i(LOG_TAG, "Initial reboot for multiple packages");
-                rebootDevice();
-            }
+            preRebootIfNecessary(mTestPackageList);
+
             mPrevRebootTime = System.currentTimeMillis();
+            int remainingPackageCount = mTestPackageList.size();
+            Log.logAndDisplay(LogLevel.INFO, LOG_TAG,
+                String.format("Start test run of %,d packages, containing %,d tests",
+                    remainingPackageCount, totalTestCount));
+            IAbi currentAbi = null;
 
-            while (!mRemainingTestPkgs.isEmpty()) {
-                TestPackage knownTests = mRemainingTestPkgs.get(0);
-                ResultFilter filter = new ResultFilter(listener, knownTests);
-                filters.add(filter);
+            for (int i = mLastTestPackageIndex; i < mTestPackageList.size(); i++) {
+                TestPackage testPackage = mTestPackageList.get(i);
 
-                IRemoteTest test = knownTests.getTestForPackage();
+                if (currentAbi == null ||
+                    !currentAbi.getName().equals(testPackage.getAbi().getName())) {
+                    currentAbi = testPackage.getAbi();
+                    installPrerequisiteApks(
+                        prerequisiteApks.get(currentAbi.getName()), currentAbi);
+                }
+
+                IRemoteTest test = testPackage.getTestForPackage();
                 if (test instanceof IBuildReceiver) {
                     ((IBuildReceiver) test).setBuild(mBuildInfo);
                 }
@@ -478,15 +526,15 @@
                     ((DeqpTestRunner)test).setCollectLogs(mCollectDeqpLogs);
                 }
 
-                forwardPackageDetails(knownTests.getPackageDef(), listener);
-                test.run(filter);
-                mRemainingTestPkgs.remove(0);
-                if (mRemainingTestPkgs.size() > 0) {
-                    rebootIfNecessary(knownTests, mRemainingTestPkgs.get(0));
-                    // remove artifacts like status bar from the previous test.
-                    // But this cannot dismiss dialog popped-up.
+                forwardPackageDetails(testPackage.getPackageDef(), listener);
+                test.run(filterMap.get(testPackage.getPackageDef().getId()));
+                if (i < mTestPackageList.size() - 1) {
+                    TestPackage nextPackage = mTestPackageList.get(i + 1);
+                    rebootIfNecessary(testPackage, nextPackage);
                     changeToHomeScreen();
                 }
+                // Track of the last complete test package index for resume
+                mLastTestPackageIndex = i;
             }
 
             if (mScreenshot) {
@@ -507,12 +555,54 @@
             CLog.e(e);
             throw e;
         } finally {
-            for (ResultFilter filter : filters) {
+            for (ResultFilter filter : filterMap.values()) {
                 filter.reportUnexecutedTests();
             }
         }
     }
 
+    /**
+     * @param allTestPackageDefList The package list to filter
+     * @param deviceAbiSet The ABIs supported by the device being tested
+     * @return A {@link List} of {@link ITestPackageDef}s that should be tested
+     */
+    private static List<ITestPackageDef> filterByAbi(
+            List<ITestPackageDef> allTestPackageDefList, Set<String> deviceAbiSet) {
+        List<ITestPackageDef> filteredTestPackageDefList = new LinkedList<>();
+        for (ITestPackageDef testPackageDef : allTestPackageDefList) {
+            if (deviceAbiSet.contains(testPackageDef.getAbi().getName())) {
+                // We only need test packages that are not empty and of matching ABIs
+                filteredTestPackageDefList.add(testPackageDef);
+            }
+        }
+        return filteredTestPackageDefList;
+    }
+
+    /** Reboot then the device iff the list of packages exceeds the minimum */
+    private void preRebootIfNecessary(List<TestPackage> testPackageList)
+            throws DeviceNotAvailableException {
+        if (mDisableReboot) {
+            return;
+        }
+
+        Set<String> packageNameSet = new HashSet<>();
+        for (TestPackage testPackage : testPackageList) {
+            // Parse the package name
+            packageNameSet.add(AbiUtils.parseTestName(testPackage.getPackageDef().getId()));
+        }
+        if (packageNameSet.size() < mMinPreRebootPackageCount) {
+            // There is actually only one unique package name. No need to reboot.
+            return;
+        }
+
+        // Reboot is needed
+        Log.logAndDisplay(LogLevel.INFO, LOG_TAG,
+            String.format("Pre-test reboot (%,d packages). Use --disable-reboot to skip",
+                packageNameSet.size()));
+
+        rebootDevice();
+    }
+
     private void rebootIfNecessary(TestPackage testFinished, TestPackage testToRun)
             throws DeviceNotAvailableException {
         // If there comes spurious failure like INJECT_EVENTS for a package,
@@ -567,6 +657,10 @@
         }
     }
 
+    /**
+     * Remove artifacts like status bar from the previous test.
+     * But this cannot dismiss dialog popped-up.
+     */
     private void changeToHomeScreen() throws DeviceNotAvailableException {
         final String homeCmd = "input keyevent 3";
 
@@ -577,89 +671,94 @@
             //ignore
         }
     }
+
     /**
-     * Build the list of test packages to run
-     * @throws DeviceNotAvailableException
+     * Set {@code mTestPackageList} to the list of test packages to run filtered by ABI.
      */
-    private List<TestPackage> buildTestsToRun() throws DeviceNotAvailableException {
-        Set<String> abis = getAbis();
-        if (abis == null || abis.isEmpty()) {
-            throw new IllegalArgumentException("could not get device's ABIs");
+    private void setupTestPackageList(Set<String> abis) throws DeviceNotAvailableException {
+        if (!mTestPackageList.isEmpty()) {
+            Log.logAndDisplay(LogLevel.INFO, LOG_TAG, "Resume tests using existing package list");
+            return;
         }
-        List<TestPackage> testPkgList = new LinkedList<TestPackage>();
         try {
-            ITestPackageRepo testRepo = createTestCaseRepo(abis);
-            Collection<ITestPackageDef> testPkgDefs = getTestPackagesToRun(testRepo, abis);
-            for (ITestPackageDef testPkgDef : testPkgDefs) {
-                addTestPackage(testPkgList, testPkgDef);
+            // Collect ALL tests
+            ITestPackageRepo testRepo = createTestCaseRepo();
+            List<ITestPackageDef> testPkgDefs = new ArrayList<>(getAvailableTestPackages(testRepo));
+            testPkgDefs = filterByAbi(testPkgDefs, abis);
+            // Note: run() relies on the fact that the list is reliably sorted for sharding purposes
+            Collections.sort(testPkgDefs);
+            // Create test package list.
+            List<TestPackage> testPackageList = new ArrayList<>();
+            for (ITestPackageDef testPackageDef : testPkgDefs) {
+                // Note: createTest filters the test list inside of testPackageDef by exclusion list
+                IRemoteTest testForPackage = testPackageDef.createTest(mCtsBuild.getTestCasesDir());
+                if (testPackageDef.getTests().size() > 0) {
+                    testPackageList.add(new TestPackage(testPackageDef, testForPackage));
+                }
             }
-            if (testPkgList.isEmpty()) {
-                Log.logAndDisplay(LogLevel.WARN, LOG_TAG, "No tests to run");
+
+            // Filter by shard
+            int numTestPackages = testPackageList.size();
+            int totalShards = Math.min(mTotalShards, numTestPackages);
+
+            List<TestPackage> shardTestPackageList = new ArrayList<>();
+            for (int i = mShardAssignment; i < numTestPackages; i += totalShards) {
+                shardTestPackageList.add(testPackageList.get(i));
             }
+            mTestPackageList.addAll(shardTestPackageList);
         } catch (FileNotFoundException e) {
-            throw new IllegalArgumentException("failed to find CTS plan file", e);
+            throw new IllegalArgumentException("failed to find XTS plan file", e);
         } catch (ParseException e) {
-            throw new IllegalArgumentException("failed to parse CTS plan file", e);
+            throw new IllegalArgumentException("failed to parse XTS plan file", e);
         } catch (ConfigurationException e) {
             throw new IllegalArgumentException("failed to process arguments", e);
         }
-        return testPkgList;
     }
 
     /**
-     * Adds a test package to the list of packages to test
+     * Return the {@link Set} of {@link ITestPackageDef}s to run unfiltered by ABI
      *
-     * @param testList
-     * @param testPkgDef
-     */
-    private void addTestPackage(List<TestPackage> testList, ITestPackageDef testPkgDef) {
-        IRemoteTest testForPackage = testPkgDef.createTest(mCtsBuild.getTestCasesDir());
-        if (testForPackage != null) {
-            Collection<TestIdentifier> knownTests = testPkgDef.getTests();
-            testList.add(new TestPackage(testPkgDef, testForPackage, knownTests));
-        }
-    }
-
-    /**
-     * Return the list of test package defs to run
-     *
-     * @return the list of test package defs to run
+     * @return the {@link Set} of {@link ITestPackageDef}s to run
      * @throws ParseException
      * @throws FileNotFoundException
      * @throws ConfigurationException
      */
-    private Collection<ITestPackageDef> getTestPackagesToRun(ITestPackageRepo testRepo,
-            Set<String> abis) throws ParseException, FileNotFoundException, ConfigurationException {
+    private Set<ITestPackageDef> getAvailableTestPackages(ITestPackageRepo testRepo)
+                throws ParseException, FileNotFoundException, ConfigurationException {
         // use LinkedHashSet to have predictable iteration order
-        Set<ITestPackageDef> testPkgDefs = new LinkedHashSet<ITestPackageDef>();
+        Set<ITestPackageDef> testPkgDefs = new LinkedHashSet<>();
         if (mPlanName != null) {
             Log.i(LOG_TAG, String.format("Executing CTS test plan %s", mPlanName));
             File ctsPlanFile = mCtsBuild.getTestPlanFile(mPlanName);
-            ITestPlan plan = createPlan(mPlanName, abis);
+            ITestPlan plan = createPlan(mPlanName);
             plan.parse(createXmlStream(ctsPlanFile));
-            for (String id : plan.getTestIds()) {
-                if (!mExcludedPackageNames.contains(AbiUtils.parseId(id)[1])) {
-                    ITestPackageDef testPackageDef = testRepo.getTestPackage(id);
-                    if (testPackageDef != null) {
-                        testPackageDef.setTestFilter(plan.getTestFilter(id));
-                        testPkgDefs.add(testPackageDef);
-                    } else {
-                        CLog.e("Could not find test package id %s referenced in plan %s", id,
-                                mPlanName);
-                    }
+
+            for (String testId : plan.getTestIds()) {
+                if (mExcludedPackageNames.contains(AbiUtils.parseTestName(testId))) {
+                    continue;
                 }
+                ITestPackageDef testPackageDef = testRepo.getTestPackage(testId);
+                if (testPackageDef == null) {
+                    CLog.e("Could not find test id %s referenced in plan %s", testId, mPlanName);
+                    continue;
+                }
+
+                testPackageDef.setTestFilter(plan.getTestFilter(testId));
+                testPkgDefs.add(testPackageDef);
             }
         } else if (mPackageNames.size() > 0){
-            Log.i(LOG_TAG, String.format("Executing CTS test packages %s", mPackageNames));
+            Log.i(LOG_TAG, String.format("Executing XTS test packages %s", mPackageNames));
+
+            Map<String, List<ITestPackageDef>> testPackageDefMap =
+                    testRepo.getTestPackageDefsByName();
+
             for (String name : mPackageNames) {
-                Set<ITestPackageDef> testPackages = testRepo.getTestPackages(name);
-                if (!testPackages.isEmpty()) {
-                    testPkgDefs.addAll(testPackages);
-                } else {
+                if (!testPackageDefMap.containsKey(name)) {
                     throw new IllegalArgumentException(String.format(
                             "Could not find test package %s. " +
-                            "Use 'list packages' to see available packages." , name));
+                                    "Use 'list packages' to see available packages.", name));
                 }
+                testPkgDefs.addAll(testPackageDefMap.get(name));
             }
         } else if (mClassName != null) {
             Log.i(LOG_TAG, String.format("Executing CTS test class %s", mClassName));
@@ -681,15 +780,19 @@
             String uniquePlanName = Long.toString(System.currentTimeMillis());
             PlanCreator planCreator = new PlanCreator(uniquePlanName, mContinueSessionId,
                     CtsTestStatus.NOT_EXECUTED);
-            ITestPlan plan = createPlan(planCreator, abis);
-            for (String id : plan.getTestIds()) {
-                if (!mExcludedPackageNames.contains(AbiUtils.parseId(id)[1])) {
-                    ITestPackageDef testPackageDef = testRepo.getTestPackage(id);
-                    if (testPackageDef != null) {
-                        testPackageDef.setTestFilter(plan.getTestFilter(id));
-                        testPkgDefs.add(testPackageDef);
-                    }
+            ITestPlan plan = createPlan(planCreator);
+            for (String testId : plan.getTestIds()) {
+                if (mExcludedPackageNames.contains(AbiUtils.parseTestName(testId))) {
+                    continue;
                 }
+                ITestPackageDef testPackageDef = testRepo.getTestPackage(testId);
+                if (testPackageDef == null) {
+                    CLog.e("Could not find test id %s referenced in plan %s", testId, mPlanName);
+                    continue;
+                }
+
+                testPackageDef.setTestFilter(plan.getTestFilter(testId));
+                testPkgDefs.add(testPackageDef);
             }
         } else {
             // should never get here - was checkFields() not called?
@@ -700,10 +803,11 @@
 
     /**
      * Return the list of unique prerequisite Android package names
-     * @param testPackages
+     *
+     * @param testPackages The {@link TestPackage}s that contain prerequisites
      */
     private Collection<String> getPrerequisitePackageNames(List<TestPackage> testPackages) {
-        Set<String> pkgNames = new HashSet<String>();
+        Set<String> pkgNames = new HashSet<>();
         for (TestPackage testPkg : testPackages) {
             String pkgName = testPkg.mPackageDef.getTargetPackageName();
             if (pkgName != null) {
@@ -714,12 +818,12 @@
     }
 
     /**
-     * @return a {@link Set} containing {@ITestPackageDef}s pertaining to the given
+     * @return a {@link Set} containing {@link ITestPackageDef}s pertaining to the given
      *     {@code className} and {@code methodName}.
      */
     private static Set<ITestPackageDef> buildTestPackageDefSet(
             ITestPackageRepo testRepo, String className, String methodName) {
-        Set<ITestPackageDef> testPkgDefs = new LinkedHashSet<ITestPackageDef>();
+        Set<ITestPackageDef> testPkgDefs = new LinkedHashSet<>();
         // try to find packages to run from class name
         List<String> packageIds = testRepo.findPackageIdsForTest(className);
         if (packageIds.isEmpty()) {
@@ -737,18 +841,33 @@
     }
 
     /**
-     * Return the list of unique prerequisite apks to install
-     * @param testPackages
+     * Return the list (by abi) of unique prerequisite apks to install
+     *
+     * @param testPackages The {@link List} of {@link TestPackage} that contain prerequisite APKs
      */
-    private Collection<String> getPrerequisiteApks(List<TestPackage> testPackages) {
-        Set<String> apkNames = new HashSet<String>();
+    private Map<String, Set<String>> getPrerequisiteApks(
+            List<TestPackage> testPackages, Set<String> abiSet) {
+        Map<String, Set<String>> abiToApkMap = new HashMap<>();
         for (TestPackage testPkg : testPackages) {
-            String apkName = testPkg.mPackageDef.getTargetApkName();
-            if (apkName != null) {
-                apkNames.add(apkName);
+            if (testPkg.getKnownTests().size() == 0) {
+                // No tests, no point in installing pre-reqs
+                continue;
             }
+            String apkName = testPkg.mPackageDef.getTargetApkName();
+            if (apkName == null) {
+                continue;
+            }
+            String abiName = testPkg.getAbi().getName();
+            if (!abiSet.contains(abiName)) {
+                continue;
+            }
+
+            if (!abiToApkMap.containsKey(abiName)) {
+                abiToApkMap.put(abiName, new HashSet<String>());
+            }
+            abiToApkMap.get(abiName).add(apkName);
         }
-        return apkNames;
+        return abiToApkMap;
     }
 
     /**
@@ -757,18 +876,20 @@
      *
      * Install the collection of test apk file names
      *
-     * @param prerequisiteApks
+     * @param prerequisiteApks The APKs that must be installed
      * @throws DeviceNotAvailableException
      */
-    private void installPrerequisiteApks(Collection<String> prerequisiteApks)
+    private void installPrerequisiteApks(Collection<String> prerequisiteApks, IAbi abi)
             throws DeviceNotAvailableException {
+        if (prerequisiteApks == null) {
+            return;
+        }
+        Log.logAndDisplay(LogLevel.INFO, LOG_TAG, "Installing prerequisites");
         for (String apkName : prerequisiteApks) {
             try {
                 File apkFile = mCtsBuild.getTestApp(apkName);
-                String errorCode = null;
-                String abi = AbiFormatter.getDefaultAbi(getDevice(), mForceAbi);
-                String[] options = {AbiUtils.createAbiFlag(abi)};
-                errorCode = getDevice().installPackage(apkFile, true, options);
+                String[] options = {AbiUtils.createAbiFlag(abi.getName())};
+                String errorCode = getDevice().installPackage(apkFile, true, options);
                 if (errorCode != null) {
                     CLog.e("Failed to install %s. Reason: %s", apkName, errorCode);
                 }
@@ -781,7 +902,7 @@
     /**
      * Uninstalls the collection of android package names from device.
      *
-     * @param uninstallPackages
+     * @param uninstallPackages The packages that must be uninstalled
      */
     private void uninstallPrequisiteApks(Collection<String> uninstallPackages)
             throws DeviceNotAvailableException {
@@ -799,34 +920,17 @@
             return null;
         }
         checkFields();
-        List<TestPackage> allTests = null;
-        try {
-            allTests = buildTestsToRun();
-        } catch (DeviceNotAvailableException e) {
-            e.printStackTrace();
+
+        List<IRemoteTest> shardQueue = new LinkedList<>();
+        for (int shardAssignment = 0; shardAssignment < mShards; shardAssignment++) {
+            CtsTest ctsTest = new CtsTest(shardAssignment, mShards /* totalShards */);
+            OptionCopier.copyOptionsNoThrow(this, ctsTest);
+            // Set the shard count because the copy option on the previous line copies
+            // over the mShard value
+            ctsTest.mShards = 0;
+            shardQueue.add(ctsTest);
         }
 
-        if (allTests == null || allTests.size() <= 1) {
-            Log.w(LOG_TAG, "no tests to shard!");
-            return null;
-        }
-
-        // treat shardQueue as a circular queue, to sequentially distribute tests among shards
-        Queue<IRemoteTest> shardQueue = new LinkedList<IRemoteTest>();
-        // don't create more shards than the number of tests we have!
-        for (int i = 0; i < mShards && i < allTests.size(); i++) {
-            CtsTest shard = new CtsTest();
-            OptionCopier.copyOptionsNoThrow(this, shard);
-            shard.mShards = 0;
-            shard.mRemainingTestPkgs = new LinkedList<TestPackage>();
-            shardQueue.add(shard);
-        }
-        while (!allTests.isEmpty()) {
-            TestPackage testPair = allTests.remove(0);
-            CtsTest shard = (CtsTest)shardQueue.poll();
-            shard.mRemainingTestPkgs.add(testPair);
-            shardQueue.add(shard);
-        }
         return shardQueue;
     }
 
@@ -851,8 +955,8 @@
      * <p/>
      * Exposed for unit testing
      */
-    ITestPackageRepo createTestCaseRepo(Set<String> abis) {
-        return new TestPackageRepo(mCtsBuild.getTestCasesDir(), abis, mIncludeKnownFailures);
+    ITestPackageRepo createTestCaseRepo() {
+        return new TestPackageRepo(mCtsBuild.getTestCasesDir(), mIncludeKnownFailures);
     }
 
     /**
@@ -860,8 +964,8 @@
      * <p/>
      * Exposed for unit testing
      */
-    ITestPlan createPlan(String planName, Set<String> abis) {
-        return new TestPlan(planName, abis);
+    ITestPlan createPlan(String planName) {
+        return new TestPlan(planName, AbiUtils.getAbisSupportedByCts());
     }
 
     /**
@@ -873,13 +977,12 @@
      */
     Set<String> getAbis() throws DeviceNotAvailableException {
         String bitness = (mForceAbi == null) ? "" : mForceAbi;
-        Set<String> abis = new HashSet<String>();
+        Set<String> abis = new HashSet<>();
         for (String abi : AbiFormatter.getSupportedAbis(mDevice, bitness)) {
             if (AbiUtils.isAbiSupportedByCts(abi)) {
                 abis.add(abi);
             }
         }
-        Log.logAndDisplay(LogLevel.INFO, LOG_TAG, "ABIs: " + abis);
         return abis;
     }
 
@@ -889,9 +992,9 @@
      * Exposed for unit testing
      * @throws ConfigurationException
      */
-    ITestPlan createPlan(PlanCreator planCreator, Set<String> abis)
+    ITestPlan createPlan(PlanCreator planCreator)
             throws ConfigurationException {
-        return planCreator.createDerivedPlan(mCtsBuild, abis);
+        return planCreator.createDerivedPlan(mCtsBuild, AbiUtils.getAbisSupportedByCts());
     }
 
     /**
@@ -931,7 +1034,7 @@
      * @return <code>true</code> if one and only one of <var>args</code> is <code>true</code>.
      *         Otherwise return <code>false</code>.
      */
-    private boolean xor(boolean... args) {
+    private static boolean xor(boolean... args) {
         boolean currentVal = args[0];
         for (int i=1; i < args.length; i++) {
             if (currentVal && args[i]) {
@@ -945,10 +1048,10 @@
     /**
      * Forward the digest and package name to the listener as a metric
      *
-     * @param listener
+     * @param listener Handles test results
      */
-    private void forwardPackageDetails(ITestPackageDef def, ITestInvocationListener listener) {
-        Map<String, String> metrics = new HashMap<String, String>(3);
+    private static void forwardPackageDetails(ITestPackageDef def, ITestInvocationListener listener) {
+        Map<String, String> metrics = new HashMap<>(3);
         metrics.put(PACKAGE_NAME_METRIC, def.getName());
         metrics.put(PACKAGE_ABI_METRIC, def.getAbi().getName());
         metrics.put(PACKAGE_DIGEST_METRIC, def.getDigest());
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/GeeTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/GeeTest.java
index 9bfe151..6c2ed65 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/GeeTest.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/GeeTest.java
@@ -49,9 +49,9 @@
     private CtsBuildHelper mCtsBuild;
     private ITestDevice mDevice;
     private IAbi mAbi;
+    private String mExeName;
 
     private final String mPackageName;
-    private final String mExeName;
 
     public GeeTest(String packageName, String exeName) {
         mPackageName = packageName;
@@ -63,6 +63,7 @@
      */
     public void setAbi(IAbi abi) {
         mAbi = abi;
+        mExeName += mAbi.getBitness();
     }
 
     @Override
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageDef.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageDef.java
index ea01535..8a5c822 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageDef.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageDef.java
@@ -28,7 +28,7 @@
  * <p/>
  * Knows how to translate this info into a runnable {@link IRemoteTest}.
  */
-public interface ITestPackageDef {
+public interface ITestPackageDef extends Comparable<ITestPackageDef> {
 
     /**
      * Get the id of the test package.
@@ -37,12 +37,6 @@
     public String getId();
 
     /**
-     * Get the appPackageName of the test package.
-     * @return the {@link String} appPackageName
-     */
-    public String getAppPackageName();
-
-    /**
      * Creates a runnable {@link IRemoteTest} from info stored in this definition.
      *
      * @param testCaseDir {@link File} representing directory of test case data
@@ -52,22 +46,6 @@
     public IRemoteTest createTest(File testCaseDir);
 
     /**
-     * Determine if given test is defined in this package.
-     *
-     * @param testDef the {@link TestIdentifier}
-     * @return <code>true</code> if test is defined
-     */
-    public boolean isKnownTest(TestIdentifier testDef);
-
-    /**
-     * Determine if given test class is defined in this package.
-     *
-     * @param testClassName the fully qualified test class name
-     * @return <code>true</code> if test class is defined
-     */
-    public boolean isKnownTestClass(String testClassName);
-
-    /**
      * Get the collection of tests in this test package.
      */
     public Collection<TestIdentifier> getTests();
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageRepo.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageRepo.java
index d1d4111..234f437 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageRepo.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPackageRepo.java
@@ -19,7 +19,7 @@
 import com.android.cts.util.AbiUtils;
 
 import java.util.List;
-import java.util.Set;
+import java.util.Map;
 
 /**
  * Interface for accessing tests from the CTS repository.
@@ -36,12 +36,19 @@
     public ITestPackageDef getTestPackage(String id);
 
     /**
-     * Get a {@link Set} of {@link TestPackageDef} given a name
-     *
-     * @param name the string package name
-     * @return a {@link Set} of {@link TestPackageDef}
+     * @return a sorted {@link List} of all package ids found in repo.
      */
-    public Set<ITestPackageDef> getTestPackages(String name);
+    public List<String> getPackageIds();
+
+    /**
+     * @return a sorted {@link List} of test package names
+     */
+    public List<String> getPackageNames();
+
+    /**
+     * @return A {@link Map} of test package name to a {@link List} of {@link ITestPackageDef}s.
+     */
+    public Map<String, List<ITestPackageDef>> getTestPackageDefsByName();
 
     /**
      * Attempt to find the package ids for a given test class name
@@ -50,15 +57,4 @@
      * @return a {@link List} of package ids.
      */
     public List<String> findPackageIdsForTest(String testClassName);
-
-    /**
-     * @return a sorted {@link List} of all package ids found in repo.
-     */
-    public List<String> getPackageIds();
-
-    /**
-     * @return a sorted {@link List} of all package names found in repo.
-     */
-    public List<String> getPackageNames();
-
 }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPlan.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPlan.java
index 21b2d0a..2d5f4a7 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPlan.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ITestPlan.java
@@ -23,6 +23,7 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.Collection;
+import java.util.List;
 
 /**
  * Interface for accessing test plan data.
@@ -42,6 +43,11 @@
     public Collection<String> getTestIds();
 
     /**
+     * Gets a sorted {@link List} of test names contained in this plan.
+     */
+    public List<String> getTestNames();
+
+    /**
      * Gets the {@link TestFilter} that should be used to filter tests from given package.
      */
     public TestFilter getTestFilter(String id);
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ResultFilter.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ResultFilter.java
index 7931660..f4f2f5d 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ResultFilter.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ResultFilter.java
@@ -24,9 +24,7 @@
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -135,4 +133,9 @@
         }
         super.testRunEnded(0, new HashMap<String, String>());
     }
+
+    /** @return the number of known tests */
+    public int getKnownTestCount() {
+        return mKnownTests.size();
+    }
 }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
index 2eccb50..9ef6257 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
@@ -112,11 +112,7 @@
         mAppPackageName = appPackageName;
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getAppPackageName() {
+    String getAppPackageName() {
         return mAppPackageName;
     }
 
@@ -124,10 +120,6 @@
         mRunTimeArgs = runTimeArgs;
     }
 
-    String getRunTimeArgs() {
-        return mRunTimeArgs;
-    }
-
     void setAppNameSpace(String appNameSpace) {
         mAppNameSpace = appNameSpace;
     }
@@ -374,19 +366,7 @@
         return mTestFilter.filter(mTests);
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean isKnownTest(TestIdentifier testDef) {
-        return mTests.contains(testDef);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean isKnownTestClass(String className) {
+    boolean isKnownTestClass(String className) {
         return mTestClasses.contains(className);
     }
 
@@ -471,10 +451,15 @@
      * @return The hex encoded string.
      */
     private String toHexString(byte[] arr) {
-        StringBuffer buf = new StringBuffer(arr.length * 2);
+        StringBuilder buf = new StringBuilder(arr.length * 2);
         for (byte b : arr) {
             buf.append(String.format("%02x", b & 0xFF));
         }
         return buf.toString();
     }
+
+    @Override
+    public int compareTo(ITestPackageDef testPackageDef) {
+        return getId().compareTo(testPackageDef.getId());
+    }
 }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageRepo.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageRepo.java
index ce91a8a..aea6613 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageRepo.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageRepo.java
@@ -40,31 +40,21 @@
 
     private static final String LOG_TAG = "TestCaseRepo";
 
-    private final File mTestCaseDir;
-
     /** mapping of ABI to a mapping of appPackageName to test definition */
     private final Map<String, Map<String, TestPackageDef>> mTestMap;
-    /** set of ABIs */
-    private final Set<String> mAbis;
     private final boolean mIncludeKnownFailures;
 
     /**
      * Creates a {@link TestPackageRepo}, initialized from provided repo files
      *
      * @param testCaseDir directory containing all test case definition xml and build files
-     * @param abis Holds the ABIs which the test must be run against. This must be a subset of the
      * ABIs supported by the device under test.
      * @param includeKnownFailures Whether to run tests which are known to fail.
      */
-    public TestPackageRepo(File testCaseDir, Set<String> abis, boolean includeKnownFailures) {
-        mTestCaseDir = testCaseDir;
-        mTestMap = new HashMap<String, Map<String, TestPackageDef>>();
-        mAbis = abis;
-        for (String abi : abis) {
-            mTestMap.put(abi, new HashMap<String, TestPackageDef>());
-        }
+    public TestPackageRepo(File testCaseDir, boolean includeKnownFailures) {
+        mTestMap = new HashMap<>();
         mIncludeKnownFailures = includeKnownFailures;
-        parse(mTestCaseDir);
+        parse(testCaseDir);
     }
 
     /**
@@ -78,25 +68,22 @@
     }
 
     private void parseTestFromXml(File xmlFile)  {
-        TestPackageXmlParser parser = new TestPackageXmlParser(mAbis, mIncludeKnownFailures);
+        TestPackageXmlParser parser = new TestPackageXmlParser(mIncludeKnownFailures);
         try {
             parser.parse(createStreamFromFile(xmlFile));
             Set<TestPackageDef> defs = parser.getTestPackageDefs();
-            if (!defs.isEmpty()) {
-                for (TestPackageDef def : defs) {
-                    String name = def.getAppPackageName();
-                    String abi = def.getAbi().getName();
-                    if (def.getTests().size() > 0) {
-                        mTestMap.get(abi).put(name, def);
-                    } else {
-                        Log.i(LOG_TAG, String.format("No tests in %s for %s, skipping",
-                                name, abi));
-                    }
-                }
-            } else {
+            if (defs.isEmpty()) {
                 Log.w(LOG_TAG, String.format("Could not find test package info in xml file %s",
                         xmlFile.getAbsolutePath()));
             }
+            for (TestPackageDef def : defs) {
+                String name = def.getAppPackageName();
+                String abi = def.getAbi().getName();
+                if (!mTestMap.containsKey(abi)) {
+                    mTestMap.put(abi, new HashMap<String, TestPackageDef>());
+                }
+                mTestMap.get(abi).put(name, def);
+            }
         } catch (FileNotFoundException e) {
             Log.e(LOG_TAG, String.format("Could not find test case xml file %s",
                     xmlFile.getAbsolutePath()));
@@ -113,7 +100,7 @@
      * <p/>
      * Exposed for unit testing
      *
-     * @param xmlFile
+     * @param xmlFile The file containing the xml description of the package
      * @return stream to read data
      *
      */
@@ -150,14 +137,54 @@
      * {@inheritDoc}
      */
     @Override
-    public Set<ITestPackageDef> getTestPackages(String appPackageName) {
-        Set<ITestPackageDef> defs = new HashSet<ITestPackageDef>();
-        for (String abi : mAbis) {
-            if (mTestMap.get(abi).containsKey(appPackageName)) {
-                defs.add(mTestMap.get(abi).get(appPackageName));
+    public List<String> getPackageIds() {
+        Set<String> ids = new HashSet<>();
+        for (String abi : mTestMap.keySet()) {
+            Map<String, TestPackageDef> testNameMap = mTestMap.get(abi);
+            for (TestPackageDef testPackageDef : testNameMap.values()) {
+                ids.add(testPackageDef.getId());
             }
         }
-        return defs;
+        List<String> idList = new ArrayList<>(ids);
+        Collections.sort(idList);
+        return idList;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<String> getPackageNames() {
+        Set<String> nameSet = new HashSet<String>();
+        for (String abi : mTestMap.keySet()) {
+            Map<String, TestPackageDef> testNameMap = mTestMap.get(abi);
+            for (TestPackageDef testPackageDef : testNameMap.values()) {
+                nameSet.add(AbiUtils.parseTestName(testPackageDef.getId()));
+            }
+        }
+        List<String> nameList = new ArrayList<>(nameSet);
+        Collections.sort(nameList);
+        return nameList;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Map<String, List<ITestPackageDef>> getTestPackageDefsByName() {
+        Map<String, List<ITestPackageDef>> packageDefMap =
+                new HashMap<String, List<ITestPackageDef>>();
+
+        for (String abi : mTestMap.keySet()) {
+            Map<String, TestPackageDef> testNameMap = mTestMap.get(abi);
+            for (String packageName : testNameMap.keySet()) {
+                if (!packageDefMap.containsKey(packageName)) {
+                    packageDefMap.put(packageName, new ArrayList<ITestPackageDef>());
+                }
+                packageDefMap.get(packageName).add(testNameMap.get(packageName));
+            }
+        }
+        return packageDefMap;
     }
 
     /**
@@ -177,34 +204,4 @@
         Collections.sort(idList);
         return idList;
     }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public List<String> getPackageIds() {
-        Set<String> ids = new HashSet<String>();
-        for (String abi : mAbis) {
-            for (String name : mTestMap.get(abi).keySet()) {
-                ids.add(AbiUtils.createId(abi, name));
-            }
-        }
-        List<String> idList = new ArrayList<String>(ids);
-        Collections.sort(idList);
-        return idList;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public List<String> getPackageNames() {
-        Set<String> names = new HashSet<String>();
-        for (String abi : mAbis) {
-            names.addAll(mTestMap.get(abi).keySet());
-        }
-        List<String> packageNames = new ArrayList<String>(names);
-        Collections.sort(packageNames);
-        return packageNames;
-    }
 }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageXmlParser.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageXmlParser.java
index 8f4f1b0..baceb8b 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageXmlParser.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageXmlParser.java
@@ -40,18 +40,14 @@
 
     private static final String LOG_TAG = "TestPackageXmlParser";
 
-    private final Set<String> mAbis;
     private final boolean mIncludeKnownFailures;
 
     private Map<String, TestPackageDef> mPackageDefs = new HashMap<String, TestPackageDef>();
 
     /**
-     * @param abis Holds the ABIs which the test must be run against. This must be a subset of the
-     * ABIs supported by the device under test.
      * @param includeKnownFailures Whether to run tests which are known to fail.
      */
-    public TestPackageXmlParser(Set<String> abis, boolean includeKnownFailures) {
-        mAbis = abis;
+    public TestPackageXmlParser(boolean includeKnownFailures) {
         mIncludeKnownFailures = includeKnownFailures;
     }
 
@@ -88,7 +84,7 @@
                 final String runTimeArgs = attributes.getValue("runtimeArgs");
                 final String testType = getTestType(attributes);
 
-                for (String abiName : mAbis) {
+                for (String abiName : AbiUtils.getAbisSupportedByCts()) {
                     Abi abi = new Abi(abiName, AbiUtils.getBitness(abiName));
                     TestPackageDef packageDef = new TestPackageDef();
                     packageDef.setAppPackageName(appPackageName);
@@ -154,13 +150,11 @@
                         Set<String> abis = new HashSet<String>();
                         if (abiList == null) {
                             // If no specification, add all supported abis
-                            abis.addAll(mAbis);
+                            abis.addAll(AbiUtils.getAbisSupportedByCts());
                         } else {
-                            for (String abi : abiList.split(", ")) {
-                                if (mAbis.contains(abi)) {
-                                    // Else only add the abi which are supported
-                                    abis.add(abi);
-                                }
+                            for (String abi : abiList.split(",")) {
+                                // Else only add the abi which are supported
+                                abis.add(abi.trim());
                             }
                         }
                         for (String abi : abis) {
@@ -206,9 +200,9 @@
     }
 
     /**
-     * @returns the set of {@link TestPackageDef} containing data parsed from xml
+     * @return the set of {@link TestPackageDef} containing data parsed from xml
      */
     public Set<TestPackageDef> getTestPackageDefs() {
-        return new HashSet<TestPackageDef>(mPackageDefs.values());
+        return new HashSet<>(mPackageDefs.values());
     }
 }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPlan.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPlan.java
index 8737db6..2419784 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPlan.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPlan.java
@@ -35,6 +35,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.TreeSet;
 
 /**
  * Implementation of {@link TestPlan}.
@@ -150,6 +151,18 @@
      * {@inheritDoc}
      */
     @Override
+    public List<String> getTestNames() {
+        TreeSet<String> testNameSet = new TreeSet<>();
+        for (String id : mIdFilterMap.keySet()) {
+            testNameSet.add(AbiUtils.parseTestName(id));
+        }
+        return new ArrayList<>(testNameSet);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
     public TestFilter getTestFilter(String id) {
         return mIdFilterMap.get(id);
     }
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/UnitTests.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/UnitTests.java
index 22dd6d9..ad1430e 100644
--- a/tools/tradefed-host/tests/src/com/android/cts/tradefed/UnitTests.java
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/UnitTests.java
@@ -21,6 +21,7 @@
 import com.android.cts.tradefed.result.TestResultsTest;
 import com.android.cts.tradefed.result.TestSummaryXmlTest;
 import com.android.cts.tradefed.result.TestTest;
+import com.android.cts.tradefed.result.TestLogTest;
 import com.android.cts.tradefed.testtype.Abi;
 import com.android.cts.tradefed.testtype.CtsTestTest;
 import com.android.cts.tradefed.testtype.DeqpTestRunnerTest;
@@ -55,6 +56,7 @@
         addTestSuite(TestResultsTest.class);
         addTestSuite(TestSummaryXmlTest.class);
         addTestSuite(TestTest.class);
+        addTestSuite(TestLogTest.class);
 
         // testtype package
         addTestSuite(CtsTestTest.class);
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/CtsXmlResultReporterTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/CtsXmlResultReporterTest.java
index 48f1ba5..ae4a41e 100644
--- a/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/CtsXmlResultReporterTest.java
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/CtsXmlResultReporterTest.java
@@ -22,6 +22,8 @@
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.build.IFolderBuildInfo;
 import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.LogDataType;
+import com.android.tradefed.result.LogFile;
 import com.android.tradefed.result.TestSummary;
 import com.android.tradefed.result.XmlResultReporter;
 import com.android.tradefed.util.FileUtil;
@@ -162,6 +164,8 @@
         mResultReporter.testFailed(testId, trace);
         mResultReporter.testEnded(testId, emptyMap);
         mResultReporter.testRunEnded(3, emptyMap);
+        mResultReporter.testLogSaved("logcat-foo-bar", LogDataType.TEXT, null,
+                new LogFile("path", "url"));
         mResultReporter.invocationEnded(1);
         String output = getOutput();
         // TODO: consider doing xml based compare
@@ -171,6 +175,52 @@
                 "<FailedScene message=\"this is a trace&#10;more trace\">     " +
                 "<StackTrace>this is a tracemore traceyet more trace</StackTrace>";
         assertTrue(output.contains(failureTag));
+
+        // Check that no TestLog tags were added, because the flag wasn't enabled.
+        final String testLogTag = String.format("<TestLog type=\"logcat\" url=\"url\" />");
+        assertFalse(output, output.contains(testLogTag));
+    }
+
+    /**
+     * Test that flips the include-test-log-tags flag and checks that logs are written to the XML.
+     */
+    public void testIncludeTestLogTags() {
+        Map<String, String> emptyMap = Collections.emptyMap();
+        final TestIdentifier testId = new TestIdentifier("FooTest", "testFoo");
+        final String trace = "this is a trace\nmore trace\nyet more trace";
+
+        // Include TestLogTags in the XML.
+        mResultReporter.setIncludeTestLogTags(true);
+
+        mResultReporter.invocationStarted(mMockBuild);
+        mResultReporter.testRunStarted(AbiUtils.createId(UnitTests.ABI.getName(), "run"), 1);
+        mResultReporter.testStarted(testId);
+        mResultReporter.testFailed(testId, trace);
+        mResultReporter.testEnded(testId, emptyMap);
+        mResultReporter.testRunEnded(3, emptyMap);
+        mResultReporter.testLogSaved("logcat-foo-bar", LogDataType.TEXT, null,
+                new LogFile("path", "url"));
+        mResultReporter.invocationEnded(1);
+
+        // Check for TestLog tags because the flag was enabled via setIncludeTestLogTags.
+        final String output = getOutput();
+        final String testLogTag = String.format("<TestLog type=\"logcat\" url=\"url\" />");
+        assertTrue(output, output.contains(testLogTag));
+    }
+
+    public void testDeviceSetup() {
+        Map<String, String> emptyMap = Collections.emptyMap();
+        final TestIdentifier testId = new TestIdentifier("android.tests.devicesetup", "TestDeviceSetup");
+        mResultReporter.invocationStarted(mMockBuild);
+        mResultReporter.testRunStarted(AbiUtils.createId(UnitTests.ABI.getName(), testId.getClassName()), 1);
+        mResultReporter.testStarted(testId);
+        mResultReporter.testEnded(testId, emptyMap);
+        mResultReporter.testRunEnded(3, emptyMap);
+        mResultReporter.invocationEnded(1);
+        String output = getOutput();
+        // TODO: consider doing xml based compare
+        final String deviceSetupTag = "appPackageName=\"android.tests.devicesetup\"";
+        assertFalse(output, output.contains(deviceSetupTag));
     }
 
     /**
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/TestLogTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/TestLogTest.java
new file mode 100644
index 0000000..55c3071
--- /dev/null
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/TestLogTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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 com.android.cts.tradefed.result;
+
+import com.android.cts.tradefed.result.TestLog.TestLogType;
+
+import org.kxml2.io.KXmlSerializer;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+import junit.framework.TestCase;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+
+/** Tests for {@link TestLog}. */
+public class TestLogTest extends TestCase {
+
+    public void testTestLogType_fromDataName() {
+        assertNull(TestLogType.fromDataName(null));
+        assertNull(TestLogType.fromDataName(""));
+        assertNull(TestLogType.fromDataName("kmsg-foo_bar_test"));
+
+        assertEquals(TestLogType.LOGCAT,
+            TestLogType.fromDataName("logcat-foo_bar_test"));
+        assertEquals(TestLogType.BUGREPORT,
+            TestLogType.fromDataName("bug-foo_bar_test"));
+    }
+
+    public void testTestLogType_getAttrValue() {
+        assertEquals("logcat", TestLogType.LOGCAT.getAttrValue());
+        assertEquals("bugreport", TestLogType.BUGREPORT.getAttrValue());
+    }
+
+    public void testFromDataName() {
+        TestLog log = TestLog.fromDataName("logcat-baz_test", "http://logs/baz_test");
+        assertEquals(TestLogType.LOGCAT, log.getLogType());
+        assertEquals("http://logs/baz_test", log.getUrl());
+    }
+
+    public void testFromDataName_unrecognizedDataName() {
+        assertNull(TestLog.fromDataName("kmsg-baz_test", null));
+    }
+
+    public void testFromDataName_nullDataName() {
+        assertNull(TestLog.fromDataName(null, "http://logs/baz_test"));
+    }
+
+    public void testFromDataName_nullUrl() {
+        assertNull(TestLog.fromDataName("logcat-bar_test", null));
+    }
+
+    public void testFromDataName_allNull() {
+        assertNull(TestLog.fromDataName(null, null));
+    }
+
+    public void testFromXml() throws Exception {
+        TestLog log = TestLog.fromXml(newXml("<TestLog type=\"logcat\" url=\"http://logs/baz_test\">"));
+        assertEquals(TestLogType.LOGCAT, log.getLogType());
+        assertEquals("http://logs/baz_test", log.getUrl());
+    }
+
+    public void testFromXml_unrecognizedType() throws Exception {
+        assertNull(TestLog.fromXml(newXml("<TestLog type=\"kmsg\" url=\"http://logs/baz_test\">")));
+    }
+
+    public void testFromXml_noTypeAttribute() throws Exception {
+        assertNull(TestLog.fromXml(newXml("<TestLog url=\"http://logs/baz_test\">")));
+    }
+
+    public void testFromXml_noUrlAttribute() throws Exception {
+        assertNull(TestLog.fromXml(newXml("<TestLog type=\"bugreport\">")));
+    }
+
+    public void testFromXml_allNull() throws Exception {
+        assertNull(TestLog.fromXml(newXml("<TestLog>")));
+    }
+
+    public void testSerialize() throws Exception {
+        KXmlSerializer serializer = new KXmlSerializer();
+        StringWriter writer = new StringWriter();
+        serializer.setOutput(writer);
+
+        TestLog log = TestLog.of(TestLogType.LOGCAT, "http://logs/foo/bar");
+        log.serialize(serializer);
+        assertEquals("<TestLog type=\"logcat\" url=\"http://logs/foo/bar\" />", writer.toString());
+    }
+
+    public void testIsTag() {
+        assertTrue(TestLog.isTag("TestLog"));
+        assertFalse(TestLog.isTag("TestResult"));
+    }
+
+    private XmlPullParser newXml(String xml) throws Exception {
+        XmlPullParserFactory factory = org.xmlpull.v1.XmlPullParserFactory.newInstance();
+        XmlPullParser parser = factory.newPullParser();
+        parser.setInput(new StringReader(xml));
+
+        // Move the parser from the START_DOCUMENT stage to the START_TAG of the data.
+        parser.next();
+
+        return parser;
+    }
+}
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/CtsTestTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/CtsTestTest.java
index 42c2ed1..30e2ba8 100644
--- a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/CtsTestTest.java
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/CtsTestTest.java
@@ -35,8 +35,10 @@
 import java.io.FileNotFoundException;
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -47,11 +49,16 @@
     private static final String PLAN_NAME = "CTS";
     private static final String PACKAGE_NAME = "test-name";
     private static final String ID = AbiUtils.createId(UnitTests.ABI.getName(), PACKAGE_NAME);
+    private static final TestIdentifier TEST_IDENTIFIER =
+            new TestIdentifier("CLASS_NAME", "TEST_NAME");
     private static final List<String> NAMES = new ArrayList<>();
     private static final List<String> IDS = new ArrayList<>();
+    private static final List<TestIdentifier> TEST_IDENTIFIER_LIST = new ArrayList<>();
+
     static {
         NAMES.add(PACKAGE_NAME);
         IDS.add(ID);
+        TEST_IDENTIFIER_LIST.add(TEST_IDENTIFIER);
     }
 
     /** the test fixture under test, with all external dependencies mocked out */
@@ -76,7 +83,7 @@
         mMockDevice = EasyMock.createMock(ITestDevice.class);
         mMockListener = EasyMock.createNiceMock(ITestInvocationListener.class);
         mStubBuildHelper = new StubCtsBuildHelper();
-        mMockPackageDefs = new HashSet<ITestPackageDef>();
+        mMockPackageDefs = new HashSet<>();
         mMockPackageDef = EasyMock.createMock(ITestPackageDef.class);
         mMockPackageDefs.add(mMockPackageDef);
         EasyMock.expect(mMockPackageDef.getTargetApkName()).andStubReturn(null);
@@ -85,17 +92,17 @@
 
         mCtsTest = new CtsTest() {
             @Override
-            ITestPackageRepo createTestCaseRepo(Set<String> abis) {
+            ITestPackageRepo createTestCaseRepo() {
                 return mMockRepo;
             }
 
             @Override
-            ITestPlan createPlan(String planName, Set<String> abis) {
+            ITestPlan createPlan(String planName) {
                 return mMockPlan;
             }
 
             @Override
-            ITestPlan createPlan(PlanCreator planCreator, Set<String> abis) {
+            ITestPlan createPlan(PlanCreator planCreator) {
                 return mMockPlan;
             }
 
@@ -110,8 +117,8 @@
         // turn off device collection for simplicity
         mCtsTest.setSkipDeviceInfo(true);
         // only run tests on one ABI
-        EasyMock.expect(mMockDevice.getProperty("ro.product.cpu.abilist")).andReturn(
-                UnitTests.ABI.getName()).anyTimes();
+        EasyMock.expect(mMockDevice.getProperty("ro.product.cpu.abilist"))
+                .andReturn(UnitTests.ABI.getName()).anyTimes();
     }
 
     /**
@@ -119,7 +126,7 @@
      */
     @SuppressWarnings("unchecked")
     public void testRun_plan() throws DeviceNotAvailableException, ParseException {
-        setParsePlanExceptations();
+        setParsePlanExpectations();
 
         setCreateAndRunTestExpectations();
 
@@ -134,6 +141,12 @@
     @SuppressWarnings("unchecked")
     public void testRun_package() throws DeviceNotAvailableException {
         mCtsTest.addPackageName(PACKAGE_NAME);
+        Map<String, List<ITestPackageDef>> nameMap = new HashMap<>();
+        List<ITestPackageDef> testPackageDefList = new ArrayList<>();
+        testPackageDefList.add(mMockPackageDef);
+        nameMap.put(PACKAGE_NAME, testPackageDefList);
+
+        EasyMock.expect(mMockRepo.getTestPackageDefsByName()).andReturn(nameMap);
 
         setCreateAndRunTestExpectations();
 
@@ -148,7 +161,12 @@
     @SuppressWarnings("unchecked")
     public void testRun_resume() throws DeviceNotAvailableException {
         mCtsTest.addPackageName(PACKAGE_NAME);
+        Map<String, List<ITestPackageDef>> nameMap = new HashMap<>();
+        List<ITestPackageDef> testPackageDefList = new ArrayList<>();
+        testPackageDefList.add(mMockPackageDef);
+        nameMap.put(PACKAGE_NAME, testPackageDefList);
 
+        EasyMock.expect(mMockRepo.getTestPackageDefsByName()).andReturn(nameMap);
         setCreateAndRunTestExpectations();
         // abort the first run
         EasyMock.expectLastCall().andThrow(new DeviceNotAvailableException());
@@ -245,7 +263,7 @@
     /**
      * Set EasyMock expectations for parsing {@link #PLAN_NAME}
      */
-    private void setParsePlanExceptations() throws ParseException {
+    private void setParsePlanExpectations() throws ParseException {
         mCtsTest.setPlanName(PLAN_NAME);
         mMockPlan.parse((InputStream) EasyMock.anyObject());
         EasyMock.expect(mMockPlan.getTestIds()).andReturn(IDS);
@@ -260,10 +278,9 @@
     private void setCreateAndRunTestExpectations() throws DeviceNotAvailableException {
         EasyMock.expect(mMockRepo.getPackageNames()).andReturn(NAMES).anyTimes();
         EasyMock.expect(mMockRepo.getPackageIds()).andReturn(IDS).anyTimes();
-        EasyMock.expect(mMockRepo.getTestPackages(PACKAGE_NAME)).andReturn(mMockPackageDefs).anyTimes();
         EasyMock.expect(mMockRepo.getTestPackage(ID)).andReturn(mMockPackageDef).anyTimes();
         EasyMock.expect(mMockPackageDef.createTest((File) EasyMock.anyObject())).andReturn(mMockTest);
-        EasyMock.expect(mMockPackageDef.getTests()).andReturn(new ArrayList<TestIdentifier>());
+        EasyMock.expect(mMockPackageDef.getTests()).andReturn(TEST_IDENTIFIER_LIST).times(2);
         EasyMock.expect(mMockPackageDef.getName()).andReturn(PACKAGE_NAME).atLeastOnce();
         EasyMock.expect(mMockPackageDef.getAbi()).andReturn(UnitTests.ABI).atLeastOnce();
         EasyMock.expect(mMockPackageDef.getId()).andReturn(ID).atLeastOnce();
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/TestPackageXmlParserTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/TestPackageXmlParserTest.java
index 5591b65..6d87a61 100644
--- a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/TestPackageXmlParserTest.java
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/TestPackageXmlParserTest.java
@@ -16,29 +16,28 @@
 
 package com.android.cts.tradefed.testtype;
 
-import com.android.cts.tradefed.command.CtsConsole;
 import com.android.cts.util.AbiUtils;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.util.xml.AbstractXmlParser.ParseException;
 
+import junit.framework.TestCase;
+
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 import java.util.Iterator;
 
-import junit.framework.TestCase;
-
 /**
  * Unit tests for {@link TestPackageXmlParser}.
  */
 public class TestPackageXmlParserTest extends TestCase {
 
-    private static String INSTR_TEST_DATA =
+    private static final String INSTR_TEST_DATA =
         "<TestPackage AndroidFramework=\"Android 1.0\" appNameSpace=\"com.example\" " +
         "appPackageName=\"android.example\" name=\"CtsExampleTestCases\" " +
         "runner=\"android.test.InstrumentationTestRunner\" version=\"1.0\">" +
         "</TestPackage>";
 
-    private static String HOST_TEST_DATA =
+    private static final String HOST_TEST_DATA =
         "<TestPackage hostSideOnly=\"true\" >\n" +
         "    <TestSuite name=\"com\" >\n" +
         "        <TestSuite name=\"example\" >\n" +
@@ -55,23 +54,22 @@
         "    </TestSuite>\n" +
         "</TestPackage>";
 
-    private static String BAD_HOST_TEST_DATA =
+    private static final String BAD_HOST_TEST_DATA =
         "<TestPackage hostSideOnly=\"blah\" >" +
         "</TestPackage>";
 
-    private static String VM_HOST_TEST_XML = "<TestPackage vmHostTest=\"true\"></TestPackage>";
+    private static final String VM_HOST_TEST_XML =
+            "<TestPackage vmHostTest=\"true\"></TestPackage>";
 
-    private static String NATIVE_TEST_XML = "<TestPackage testType=\"native\"></TestPackage>";
+    private static final String NATIVE_TEST_XML = "<TestPackage testType=\"native\"></TestPackage>";
 
-    private static String NO_TEST_DATA =
-        "<invalid />";
+    private static final String NO_TEST_DATA = "<invalid />";
 
     /**
      * Test parsing test case xml containing an instrumentation test definition.
      */
     public void testParse_instrPackage() throws ParseException  {
-        TestPackageXmlParser parser = new TestPackageXmlParser(AbiUtils.getAbisSupportedByCts(),
-                true);
+        TestPackageXmlParser parser = new TestPackageXmlParser(true);
         parser.parse(getStringAsStream(INSTR_TEST_DATA));
         for (TestPackageDef def : parser.getTestPackageDefs()) {
             assertEquals("com.example", def.getAppNameSpace());
@@ -85,8 +83,7 @@
      * Test parsing test case xml containing an host test attribute and test data.
      */
     public void testParse_hostTest() throws ParseException  {
-        TestPackageXmlParser parser = new TestPackageXmlParser(AbiUtils.getAbisSupportedByCts(),
-                true);
+        TestPackageXmlParser parser = new TestPackageXmlParser(true);
         parser.parse(getStringAsStream(HOST_TEST_DATA));
         for (TestPackageDef def : parser.getTestPackageDefs()) {
             assertEquals(TestPackageDef.HOST_SIDE_ONLY_TEST, def.getTestType());
@@ -110,8 +107,7 @@
     }
 
     public void testParse_hostTest_noKnownFailures() throws ParseException  {
-        TestPackageXmlParser parser = new TestPackageXmlParser(AbiUtils.getAbisSupportedByCts(),
-                false);
+        TestPackageXmlParser parser = new TestPackageXmlParser(false);
         parser.parse(getStringAsStream(HOST_TEST_DATA));
         for (TestPackageDef def : parser.getTestPackageDefs()) {
             assertEquals(TestPackageDef.HOST_SIDE_ONLY_TEST, def.getTestType());
@@ -134,8 +130,7 @@
      * Test parsing test case xml containing an invalid host test attribute.
      */
     public void testParse_badHostTest() throws ParseException  {
-        TestPackageXmlParser parser = new TestPackageXmlParser(AbiUtils.getAbisSupportedByCts(),
-                true);
+        TestPackageXmlParser parser = new TestPackageXmlParser(true);
         parser.parse(getStringAsStream(BAD_HOST_TEST_DATA));
         for (TestPackageDef def : parser.getTestPackageDefs()) {
             assertFalse(TestPackageDef.HOST_SIDE_ONLY_TEST.equals(def.getTestType()));
@@ -151,8 +146,7 @@
     }
 
     private void assertTestType(String expectedType, String xml) throws ParseException {
-        TestPackageXmlParser parser = new TestPackageXmlParser(AbiUtils.getAbisSupportedByCts(),
-                true);
+        TestPackageXmlParser parser = new TestPackageXmlParser(true);
         parser.parse(getStringAsStream(xml));
         for (TestPackageDef def : parser.getTestPackageDefs()) {
             assertEquals(expectedType, def.getTestType());
@@ -163,8 +157,7 @@
      * Test parsing a test case xml with no test package data.
      */
     public void testParse_noData() throws ParseException  {
-        TestPackageXmlParser parser = new TestPackageXmlParser(AbiUtils.getAbisSupportedByCts(),
-                true);
+        TestPackageXmlParser parser = new TestPackageXmlParser(true);
         parser.parse(getStringAsStream(NO_TEST_DATA));
         assertTrue(parser.getTestPackageDefs().isEmpty());
     }
diff --git a/tools/utils/Android.mk b/tools/utils/Android.mk
index 36081ca..0ba5cf4 100644
--- a/tools/utils/Android.mk
+++ b/tools/utils/Android.mk
@@ -25,6 +25,6 @@
 LOCAL_CLASSPATH := $(HOST_JDK_TOOLS_JAR)
 
 LOCAL_JAVA_LIBRARIES := junit
-LOCAL_STATIC_JAVA_LIBRARIES := vogarexpectlib
+LOCAL_STATIC_JAVA_LIBRARIES := ctsabiutilslib vogarexpectlib
 
 include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/utils/CollectAllTests.java b/tools/utils/CollectAllTests.java
index 367fb93..ed74824 100644
--- a/tools/utils/CollectAllTests.java
+++ b/tools/utils/CollectAllTests.java
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+import com.android.cts.util.AbiUtils;
 
 import org.junit.runner.RunWith;
 import org.w3c.dom.Document;
@@ -20,6 +21,7 @@
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
+import vogar.Expectation;
 import vogar.ExpectationStore;
 
 import java.io.BufferedReader;
@@ -61,9 +63,9 @@
     private static final String TEST_TYPE = "LOCAL_TEST_TYPE :";
 
     public static void main(String[] args) {
-        if (args.length < 4 || args.length > 6) {
+        if (args.length < 5 || args.length > 7) {
             System.err.println("usage: CollectAllTests <output-file> <manifest-file> <jar-file> "
-                               + "<java-package> [expectation-dir [makefile-file]]");
+                               + "<java-package> <architecture> [expectation-dir [makefile-file]]");
             if (args.length != 0) {
                 System.err.println("received:");
                 for (String arg : args) {
@@ -86,8 +88,14 @@
                 return;
             }
         }
-        String libcoreExpectationDir = (args.length > 4) ? args[4] : null;
-        String androidMakeFile = (args.length > 5) ? args[5] : null;
+        String architecture = args[4];
+        if (architecture == null || architecture.equals("")) {
+            System.err.println("Invalid architecture");
+            System.exit(1);
+            return;
+        }
+        String libcoreExpectationDir = (args.length > 5) ? args[5] : null;
+        String androidMakeFile = (args.length > 6) ? args[6] : null;
 
         final TestType testType = TestType.getTestType(androidMakeFile);
 
@@ -207,7 +215,7 @@
 
                 try {
                     klass.getConstructor(new Class<?>[] { String.class } );
-                    addToTests(expectations, testCases, klass);
+                    addToTests(expectations, architecture, testCases, klass);
                     continue;
                 } catch (NoSuchMethodException e) {
                 } catch (SecurityException e) {
@@ -218,7 +226,7 @@
 
                 try {
                     klass.getConstructor(new Class<?>[0]);
-                    addToTests(expectations, testCases, klass);
+                    addToTests(expectations, architecture, testCases, klass);
                     continue;
                 } catch (NoSuchMethodException e) {
                 } catch (SecurityException e) {
@@ -356,6 +364,7 @@
     }
 
     private static void addToTests(ExpectationStore[] expectations,
+                                   String architecture,
                                    Map<String,TestClass> testCases,
                                    Class<?> testClass) {
         Set<String> testNames = new HashSet<String>();
@@ -386,11 +395,12 @@
             }
 
             testNames.add(testName);
-            addToTests(expectations, testCases, testClass, testName);
+            addToTests(expectations, architecture, testCases, testClass, testName);
         }
     }
 
     private static void addToTests(ExpectationStore[] expectations,
+                                   String architecture,
                                    Map<String,TestClass> testCases,
                                    Class<?> test,
                                    String testName) {
@@ -412,6 +422,10 @@
             return;
         }
 
+        Set<String> supportedAbis = VogarUtils.extractSupportedAbis(architecture,
+                                                                    expectations,
+                                                                    testClassName,
+                                                                    testName);
         TestClass testClass;
         if (testCases.containsKey(testClassName)) {
             testClass = testCases.get(testClassName);
@@ -420,7 +434,8 @@
             testCases.put(testClassName, testClass);
         }
 
-        testClass.mCases.add(new TestMethod(testName, "", "", knownFailure, false, false));
+        testClass.mCases.add(new TestMethod(testName, "", "", supportedAbis,
+              knownFailure, false, false));
     }
 
     private static boolean isJunit3Test(Class<?> klass) {
diff --git a/tools/utils/DescriptionGenerator.java b/tools/utils/DescriptionGenerator.java
index 607d2e5..09e1118 100644
--- a/tools/utils/DescriptionGenerator.java
+++ b/tools/utils/DescriptionGenerator.java
@@ -22,6 +22,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
+import java.util.Set;
 
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
@@ -38,6 +39,7 @@
 import org.w3c.dom.NodeList;
 
 import vogar.ExpectationStore;
+import vogar.Expectation;
 
 import com.sun.javadoc.AnnotationDesc;
 import com.sun.javadoc.AnnotationTypeDoc;
@@ -82,11 +84,13 @@
     static final String ATTRIBUTE_VALUE_FRAMEWORK = "Android 1.0";
 
     static final String ATTRIBUTE_NAME = "name";
+    static final String ATTRIBUTE_ABIS = "abis";
     static final String ATTRIBUTE_HOST_CONTROLLER = "HostController";
 
     static final String XML_OUTPUT_PATH = "./description.xml";
 
     static final String OUTPUT_PATH_OPTION = "-o";
+    static final String ARCHITECTURE_OPTION = "-a";
 
     /**
      * Start to parse the classes passed in by javadoc, and generate
@@ -103,12 +107,21 @@
         }
 
         String outputPath = XML_OUTPUT_PATH;
+        String architecture = null;
         String[][] options = root.options();
         for (String[] option : options) {
-            if (option.length == 2 && option[0].equals(OUTPUT_PATH_OPTION)) {
-                outputPath = option[1];
+            if (option.length == 2) {
+                if (option[0].equals(OUTPUT_PATH_OPTION)) {
+                    outputPath = option[1];
+                } else if (option[0].equals(ARCHITECTURE_OPTION)) {
+                    architecture = option[1];
+                }
             }
         }
+        if (architecture == null || architecture.equals("")) {
+            Log.e("Missing architecture!", null);
+            return false;
+        }
 
         XMLGenerator xmlGenerator = null;
         try {
@@ -128,7 +141,7 @@
 
         for (ClassDoc clazz : classes) {
             if ((!clazz.isAbstract()) && (isValidJUnitTestCase(clazz))) {
-                xmlGenerator.addTestClass(new TestClass(clazz, ctsExpectationStore));
+                xmlGenerator.addTestClass(new TestClass(clazz, ctsExpectationStore, architecture));
             }
         }
 
@@ -420,6 +433,8 @@
                     Node caseNode = elem.appendChild(mDoc.createElement(TAG_TEST));
 
                     setAttribute(caseNode, ATTRIBUTE_NAME, caze.mName);
+                    String abis = caze.mAbis.toString();
+                    setAttribute(caseNode, ATTRIBUTE_ABIS, abis.substring(1, abis.length() - 1));
                     if ((caze.mController != null) && (caze.mController.length() != 0)) {
                         setAttribute(caseNode, ATTRIBUTE_HOST_CONTROLLER, caze.mController);
                     }
@@ -509,9 +524,9 @@
          *
          * @param clazz The specified ClassDoc.
          */
-        TestClass(ClassDoc clazz, ExpectationStore expectationStore) {
+        TestClass(ClassDoc clazz, ExpectationStore expectationStore, String architecture) {
             mName = clazz.toString();
-            mCases = getTestMethods(expectationStore, clazz);
+            mCases = getTestMethods(expectationStore, architecture, clazz);
         }
 
         /**
@@ -520,7 +535,8 @@
          * @param clazz The specified ClassDoc.
          * @return A collection of TestMethod.
          */
-        Collection<TestMethod> getTestMethods(ExpectationStore expectationStore, ClassDoc clazz) {
+        Collection<TestMethod> getTestMethods(ExpectationStore expectationStore,
+                String architecture, ClassDoc clazz) {
             Collection<MethodDoc> methods = getAllMethods(clazz);
 
             ArrayList<TestMethod> cases = new ArrayList<TestMethod>();
@@ -553,8 +569,13 @@
                 }
 
                 if (name.startsWith("test")) {
-                    cases.add(new TestMethod(name, method.commentText(), controller, knownFailure,
-                            isBroken, isSuppressed));
+                    Expectation expectation = expectationStore.get(
+                            VogarUtils.buildFullTestName(clazz.toString(), name));
+                    Set<String> supportedAbis =
+                            VogarUtils.extractSupportedAbis(architecture, expectation);
+                    cases.add(new TestMethod(
+                            name, method.commentText(), controller, supportedAbis,
+                                    knownFailure, isBroken, isSuppressed));
                 }
             }
 
@@ -610,6 +631,7 @@
         String mName;
         String mDescription;
         String mController;
+        Set<String> mAbis;
         String mKnownFailure;
         boolean mIsBroken;
         boolean mIsSuppressed;
@@ -621,11 +643,12 @@
          * @param description The description of the test case.
          * @param knownFailure The reason of known failure.
          */
-        TestMethod(String name, String description, String controller, String knownFailure,
-                boolean isBroken, boolean isSuppressed) {
+        TestMethod(String name, String description, String controller, Set<String> abis,
+                String knownFailure, boolean isBroken, boolean isSuppressed) {
             mName = name;
             mDescription = description;
             mController = controller;
+            mAbis = abis;
             mKnownFailure = knownFailure;
             mIsBroken = isBroken;
             mIsSuppressed = isSuppressed;
diff --git a/tools/utils/VogarUtils.java b/tools/utils/VogarUtils.java
index c7070a5..5e8b944 100644
--- a/tools/utils/VogarUtils.java
+++ b/tools/utils/VogarUtils.java
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+import com.android.cts.util.AbiUtils;
+
 import vogar.Expectation;
 import vogar.ExpectationStore;
 import vogar.ModeId;
@@ -38,12 +40,26 @@
         return false;
     }
 
+    /**
+     * @return true iff the class/name is found in the vogar known failure list and it is not
+     * a known failure that is a result of an unsupported abi.
+     */
     public static boolean isVogarKnownFailure(ExpectationStore expectationStore,
             final String testClassName,
             final String testMethodName) {
-        String fullTestName = String.format("%s#%s", testClassName, testMethodName);
-        return expectationStore != null
-                && expectationStore.get(fullTestName) != Expectation.SUCCESS;
+        if (expectationStore == null) {
+            return false;
+        }
+        String fullTestName = buildFullTestName(testClassName, testMethodName);
+        Expectation expectation = expectationStore.get(fullTestName);
+        if (expectation == Expectation.SUCCESS) {
+            return false;
+        }
+
+        String description = expectation.getDescription();
+        boolean foundAbi = AbiUtils.parseAbiList(description).size() > 0;
+
+        return expectation != Expectation.SUCCESS && !foundAbi;
     }
 
     public static ExpectationStore provideExpectationStore(String dir) throws IOException {
@@ -67,4 +83,49 @@
         }
         return expectSet;
     }
+
+    /** @return the test name in the form of com.android.myclass.TestClass#testMyMethod */
+    public static String buildFullTestName(String testClass, String testMethodName) {
+        return String.format("%s#%s", testClass, testMethodName);
+    }
+
+    /**
+     * This method looks in the description field of the Vogar entry for the ABI_LIST_MARKER
+     * and returns the list of abis found there.
+     *
+     * @return The Set of supported abis parsed from the {@code expectation}'s description.
+     */
+    public static Set<String> extractSupportedAbis(String architecture, Expectation expectation) {
+        Set<String> supportedAbiSet = AbiUtils.getAbisForArch(architecture);
+        if (expectation == null || expectation.getDescription().isEmpty()) {
+            // Include all abis since there was no limitation found in the description
+            return supportedAbiSet;
+        }
+
+        // Remove any abis that are not supported for the test.
+        supportedAbiSet.removeAll(AbiUtils.parseAbiList(expectation.getDescription()));
+
+        return supportedAbiSet;
+    }
+
+    /**
+     * Determine the correct set of ABIs for the given className/testName.
+     *
+     * @return the set of ABIs that can be expected to pass for the given combination of
+     * {@code architecture}, {@code className} and {@code testName}.
+     */
+    public static Set<String> extractSupportedAbis(String architecture,
+                                                   ExpectationStore[] expectationStores,
+                                                   String className,
+                                                   String testName) {
+
+        String fullTestName = VogarUtils.buildFullTestName(className, testName);
+        Set<String> supportedAbiSet = AbiUtils.getAbisForArch(architecture);
+        for (ExpectationStore expectationStore : expectationStores) {
+            Expectation expectation = expectationStore.get(fullTestName);
+            supportedAbiSet.retainAll(extractSupportedAbis(architecture, expectation));
+        }
+
+        return supportedAbiSet;
+    }
 }
diff --git a/tools/utils/buildCts.py b/tools/utils/buildCts.py
index 4a1b2f3..4d04e1a 100755
--- a/tools/utils/buildCts.py
+++ b/tools/utils/buildCts.py
@@ -158,7 +158,6 @@
     # CTS Stable plan
     plan = tools.TestPlan(packages)
     plan.Exclude(r'com\.android\.cts\.browserbench')
-    plan.Exclude(r'com\.android\.cts\.filesystemperf\.RandomRWTest$')
     for package, test_list in flaky_tests.iteritems():
       plan.ExcludeTests(package, test_list)
     self.__WritePlan(plan, 'CTS-stable')
@@ -167,7 +166,6 @@
     plan = tools.TestPlan(packages)
     plan.Exclude('.*')
     plan.Include(r'com\.android\.cts\.browserbench')
-    plan.Include(r'com\.android\.cts\.filesystemperf\.RandomRWTest$')
     for package, test_list in flaky_tests.iteritems():
       plan.Include(package+'$')
       plan.IncludeTests(package, test_list)
@@ -183,7 +181,6 @@
     for package, test_list in small_tests.iteritems():
       plan.Include(package+'$')
     plan.Exclude(r'com\.android\.cts\.browserbench')
-    plan.Exclude(r'com\.android\.cts\.filesystemperf\.RandomRWTest$')
     for package, test_list in flaky_tests.iteritems():
       plan.ExcludeTests(package, test_list)
     self.__WritePlan(plan, 'CTS-kitkat-small')
@@ -194,7 +191,6 @@
     for package, test_list in medium_tests.iteritems():
       plan.Include(package+'$')
     plan.Exclude(r'com\.android\.cts\.browserbench')
-    plan.Exclude(r'com\.android\.cts\.filesystemperf\.RandomRWTest$')
     for package, test_list in flaky_tests.iteritems():
       plan.ExcludeTests(package, test_list)
     self.__WritePlan(plan, 'CTS-kitkat-medium')
@@ -204,7 +200,6 @@
     plan.Exclude('.*')
     plan.Include(r'android\.hardware$')
     plan.Exclude(r'com\.android\.cts\.browserbench')
-    plan.Exclude(r'com\.android\.cts\.filesystemperf\.RandomRWTest$')
     for package, test_list in flaky_tests.iteritems():
       plan.ExcludeTests(package, test_list)
     self.__WritePlan(plan, 'CTS-hardware')
@@ -213,8 +208,8 @@
     plan = tools.TestPlan(packages)
     plan.Exclude('.*')
     plan.Include(r'android\.media$')
+    plan.Include(r'android\.view$')
     plan.Exclude(r'com\.android\.cts\.browserbench')
-    plan.Exclude(r'com\.android\.cts\.filesystemperf\.RandomRWTest$')
     for package, test_list in flaky_tests.iteritems():
       plan.ExcludeTests(package, test_list)
     self.__WritePlan(plan, 'CTS-media')
@@ -224,7 +219,6 @@
     plan.Exclude('.*')
     plan.Include(r'android\.mediastress$')
     plan.Exclude(r'com\.android\.cts\.browserbench')
-    plan.Exclude(r'com\.android\.cts\.filesystemperf\.RandomRWTest$')
     for package, test_list in flaky_tests.iteritems():
       plan.ExcludeTests(package, test_list)
     self.__WritePlan(plan, 'CTS-mediastress')
@@ -235,7 +229,6 @@
     for package, test_list in new_test_packages.iteritems():
       plan.Include(package+'$')
     plan.Exclude(r'com\.android\.cts\.browserbench')
-    plan.Exclude(r'com\.android\.cts\.filesystemperf\.RandomRWTest$')
     for package, test_list in flaky_tests.iteritems():
       plan.ExcludeTests(package, test_list)
     self.__WritePlan(plan, 'CTS-l-tests')
@@ -250,21 +243,15 @@
       plan.Exclude(package+'$')
     plan.Exclude(r'android\.hardware$')
     plan.Exclude(r'android\.media$')
+    plan.Exclude(r'android\.view$')
     plan.Exclude(r'android\.mediastress$')
     plan.Exclude(r'com\.android\.cts\.browserbench')
-    plan.Exclude(r'com\.android\.cts\.filesystemperf\.RandomRWTest$')
     for package, test_list in flaky_tests.iteritems():
       plan.ExcludeTests(package, test_list)
     self.__WritePlan(plan, 'CTS-staging')
 
     plan = tools.TestPlan(packages)
     plan.Exclude('.*')
-    plan.Include(r'android\.core\.tests\.libcore\.')
-    plan.Include(r'android\.jdwp')
-    self.__WritePlan(plan, 'CTS-ART')
-
-    plan = tools.TestPlan(packages)
-    plan.Exclude('.*')
     plan.Include(r'com\.drawelements\.')
     self.__WritePlan(plan, 'CTS-DEQP')
 
@@ -345,7 +332,6 @@
       'android.theme' : [],
       'android.usb' : [],
       'android.util' : [],
-      'android.view' : [],
       'com.android.cts.dram' : [],
       'com.android.cts.filesystemperf' : [],
       'com.android.cts.jank' : [],
@@ -359,7 +345,7 @@
 def BuildCtsVettedNewPackagesList():
   """ Construct a defaultdict that maps package names that is vetted for L. """
   return {
-      'android.appwidget' : [],
+      'android.JobScheduler' : [],
       'android.core.tests.libcore.package.harmony_annotation' : [],
       'android.core.tests.libcore.package.harmony_beans' : [],
       'android.core.tests.libcore.package.harmony_java_io' : [],
@@ -368,6 +354,7 @@
       'android.core.tests.libcore.package.harmony_java_net' : [],
       'android.core.tests.libcore.package.harmony_java_nio' : [],
       'android.core.tests.libcore.package.harmony_java_util' : [],
+      'android.core.tests.libcore.package.harmony_java_text' : [],
       'android.core.tests.libcore.package.harmony_javax_security' : [],
       'android.core.tests.libcore.package.harmony_logging' : [],
       'android.core.tests.libcore.package.harmony_prefs' : [],
@@ -384,11 +371,13 @@
       'android.tv' : [],
       'android.uiautomation' : [],
       'android.uirendering' : [],
-      'android.webgl' : []}
+      'android.webgl' : [],
+      'com.drawelements.deqp.gles3' : [],
+      'com.drawelements.deqp.gles31' : []}
 
 def BuildCtsFlakyTestList():
   """ Construct a defaultdict that maps package name to a list of tests
-      that are known to be flaky. """
+      that are known to be flaky in the lab or not passing on userdebug builds. """
   return {
       'android.app' : [
           'cts.ActivityManagerTest#testIsRunningInTestHarness',],
@@ -423,7 +412,11 @@
           'cts.SELinuxDomainTest#testSuDomain',
           'cts.SELinuxHostTest#testAllEnforcing',],
       'android.webkit' : [
-          'cts.WebViewClientTest#testOnUnhandledKeyEvent',]}
+          'cts.WebViewClientTest#testOnUnhandledKeyEvent',],
+      'com.android.cts.filesystemperf' : [
+          'RandomRWTest#testRandomRead',
+          'RandomRWTest#testRandomUpdate',],
+      '' : []}
 
 def LogGenerateDescription(name):
   print 'Generating test description for package %s' % name