am 370e2438: camera2: Move ITS tests to CTS verifier.

* commit '370e2438ab27bdc5a3339859d0e76a4165794f7a':
  camera2: Move ITS tests to CTS verifier.
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index a31014d..b3b826d 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -107,7 +107,6 @@
     CtsAdminTestCases \
     CtsAnimationTestCases \
     CtsAppTestCases \
-    CtsAppWidgetTestCases \
     CtsBluetoothTestCases \
     CtsCalendarcommon2TestCases \
     CtsContentTestCases \
@@ -122,6 +121,7 @@
     CtsGraphicsTestCases \
     CtsGraphics2TestCases \
     CtsHardwareTestCases \
+    CtsJobSchedulerDeviceTestCases \
     CtsJniTestCases \
     CtsKeystoreTestCases \
     CtsLocationTestCases \
@@ -173,6 +173,7 @@
     CtsDevicePolicyManagerTestCases \
     CtsHostJank \
     CtsHostUi \
+    CtsJdwpSecurityHostTestCases \
     CtsMonkeyTestCases \
     CtsThemeHostTestCases \
     CtsSecurityHostTestCases \
@@ -195,6 +196,7 @@
 
 cts_device_jars := \
     CtsDeviceJank \
+    CtsJdwpApp \
     CtsPrintInstrument
 
 cts_device_executables := \
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index 0b0db9d..e370c81 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 android-ex-camera2
@@ -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 ead241e..18dd5b3 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"/>
 
@@ -54,6 +54,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" />
@@ -99,6 +100,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 -->
@@ -113,7 +116,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"
@@ -130,6 +133,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"
@@ -152,6 +157,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"
@@ -234,7 +240,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>
@@ -243,7 +250,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"
@@ -333,7 +342,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>
@@ -342,9 +352,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>
@@ -353,7 +366,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.BleScannerPowerLevelActivity"
                 android:label="@string/ble_power_level_name"
@@ -377,7 +392,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>
@@ -386,7 +402,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.BleAdvertiserPowerLevelActivity"
                 android:label="@string/ble_power_level_name"
@@ -429,7 +447,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"
@@ -440,6 +458,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"
@@ -793,8 +813,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 -->
@@ -818,6 +838,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"
@@ -828,8 +850,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"
@@ -840,6 +862,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"
@@ -850,6 +874,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 -->
@@ -861,6 +887,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">
@@ -869,8 +899,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">
@@ -879,6 +913,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">
@@ -887,8 +926,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"
@@ -1001,8 +1043,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">
@@ -1014,7 +1058,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">
@@ -1061,6 +1105,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">
@@ -1069,6 +1119,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"
@@ -1116,14 +1172,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">
@@ -1132,6 +1189,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"
@@ -1141,8 +1202,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"
@@ -1155,7 +1223,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"
@@ -1169,8 +1237,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">
@@ -1194,6 +1262,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"
@@ -1203,6 +1272,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"
@@ -1212,6 +1282,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"
@@ -1221,6 +1293,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"
@@ -1230,6 +1304,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>
 
 
@@ -1240,6 +1315,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"
@@ -1257,7 +1334,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>
@@ -1270,7 +1348,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>
@@ -1298,6 +1376,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/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 154154d..a7aeeed 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.
@@ -259,7 +263,7 @@
     <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>
 
@@ -491,6 +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_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>
@@ -1175,7 +1180,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>
@@ -1285,6 +1290,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/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/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/helpers/SensorFeaturesDeactivator.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/helpers/SensorFeaturesDeactivator.java
index 82f8ae9..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.
@@ -37,6 +39,7 @@
     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();
@@ -51,6 +54,7 @@
 
         mAirplaneMode.requestToSetMode(mStateContainer, true);
         mScreenBrightnessMode.requestToSetMode(mStateContainer, false);
+        mAmbientDisplayMode.requestToSetMode(mStateContainer, false);
         mAutoRotateScreenMode.requestToSetMode(mStateContainer, false);
         mKeepScreenOnMode.requestToSetMode(mStateContainer, false);
         mLocationMode.requestToSetMode(mStateContainer, false);
@@ -70,6 +74,7 @@
 
         mAirplaneMode.requestToResetMode(mStateContainer);
         mScreenBrightnessMode.requestToResetMode(mStateContainer);
+        mAmbientDisplayMode.requestToResetMode(mStateContainer);
         mAutoRotateScreenMode.requestToResetMode(mStateContainer);
         mKeepScreenOnMode.requestToResetMode(mStateContainer);
         mLocationMode.requestToResetMode(mStateContainer);
@@ -78,6 +83,7 @@
     private void captureInitialState() {
         mAirplaneMode.captureInitialState();
         mScreenBrightnessMode.captureInitialState();
+        mAmbientDisplayMode.captureInitialState();
         mAutoRotateScreenMode.captureInitialState();
         mLocationMode.captureInitialState();
         mKeepScreenOnMode.captureInitialState();
@@ -116,6 +122,37 @@
         }
     }
 
+    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);
+        }
+    }
+
     private class AutoRotateScreenModeSettingContainer extends SensorSettingContainer {
         public AutoRotateScreenModeSettingContainer() {
             super(Settings.ACTION_ACCESSIBILITY_SETTINGS,
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/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 6720dff..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();
@@ -80,7 +83,7 @@
 
         // Ensure that we see both of our roots
         mDevice.waitForIdle();
-        assertTrue("CtsLocal root", new UiObject(new UiSelector().text("CtsLocal")).exists());
+        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());
 
@@ -241,7 +244,7 @@
         // Look around, we should be able to see both DocumentsProviders and
         // other GET_CONTENT sources.
         mDevice.waitForIdle();
-        assertTrue("CtsLocal root", new UiObject(new UiSelector().text("CtsLocal")).exists());
+        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());
 
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/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/src/com/android/cts/util/AbiUtils.java b/libs/commonutil/src/com/android/cts/util/AbiUtils.java
index 6f47d52..42336f3 100644
--- a/libs/commonutil/src/com/android/cts/util/AbiUtils.java
+++ b/libs/commonutil/src/com/android/cts/util/AbiUtils.java
@@ -157,6 +157,22 @@
     }
 
     /**
+     * @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
      */
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 9ae041c..dd8660f 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -1,5 +1,19 @@
 [
 {
+  description: "the UsageStats is not yet stable enough",
+  names: [
+    "android.app.usage.cts.UsageStatsTest"
+  ],
+  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",
@@ -8,13 +22,6 @@
   bug: 17595050
 },
 {
-  description: "signature test stil needs more work",
-  names: [
-    "android.signature.cts.SignatureTest#testSignature"
-  ],
-  bug: 17894722
-},
-{
   description: "Not all jdwp features are currently supported. These tests will fail",
   names: [
     "org.apache.harmony.jpda.tests.jdwp.DebuggerOnDemand.OnthrowDebuggerLaunchTest#testDebuggerLaunch001",
@@ -45,26 +52,6 @@
   bug: 16720689
 },
 {
-  description: "test can only run properly on a user build device when the bug is resolved",
-  names: [
-    "android.appwidget.cts.AppWidgetTest#testAppWidgetProviderCallbacks",
-    "android.appwidget.cts.AppWidgetTest#testBindAppWidget",
-    "android.appwidget.cts.AppWidgetTest#testCollectionWidgets",
-    "android.appwidget.cts.AppWidgetTest#testDeleteHost",
-    "android.appwidget.cts.AppWidgetTest#testDeleteHosts",
-    "android.appwidget.cts.AppWidgetTest#testGetAppWidgetIds",
-    "android.appwidget.cts.AppWidgetTest#testGetAppWidgetInfo",
-    "android.appwidget.cts.AppWidgetTest#testGetAppWidgetOptions",
-    "android.appwidget.cts.AppWidgetTest#testPartiallyUpdateAppWidgetViaWidgetId",
-    "android.appwidget.cts.AppWidgetTest#testPartiallyUpdateAppWidgetViaWidgetIds",
-    "android.appwidget.cts.AppWidgetTest#testTwoAppWidgetProviderCallbacks",
-    "android.appwidget.cts.AppWidgetTest#testUpdateAppWidgetViaComponentName",
-    "android.appwidget.cts.AppWidgetTest#testUpdateAppWidgetViaWidgetId",
-    "android.appwidget.cts.AppWidgetTest#testUpdateAppWidgetViaWidgetIds"
-  ],
-  bug: 17993121
-},
-{
   description: "A few WebGL tests are known to fail in WebView",
   names: [
     "android.webgl.cts.WebGLTest#test_conformance_extensions_oes_texture_float_with_video_html",
@@ -86,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",
@@ -357,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 19a94a8..7ad3682 100644
--- a/tests/expectations/unsupportedabis.txt
+++ b/tests/expectations/unsupportedabis.txt
@@ -6,10 +6,10 @@
     "android.bionic.malloc#pvalloc_std",
     "android.bionic.malloc#valloc_overflow",
     "android.bionic.malloc#valloc_std",
-    "android.sample.cts.SampleDeviceResultTest",
-    "android.sample.cts.SampleDeviceTest",
-    "android.sample.cts.SampleHostResultTest",
-    "android.sample.cts.SampleHostTest"
+    "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/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/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/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/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/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 8224481..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,12 +247,17 @@
         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) {
         mIsDeviceInfoRun = DeviceInfoCollector.IDS.contains(id);
         if (!mIsDeviceInfoRun) {
             mCurrentPkgResult = mResults.getOrCreatePackage(id);
+            mCurrentPkgResult.setDeviceSerial(mDeviceSerial);
         }
     }
 
@@ -235,7 +267,7 @@
     @Override
     public void testStarted(TestIdentifier test) {
         if (!mIsDeviceInfoRun) {
-            mCurrentPkgResult.insertTest(test);
+            mCurrentTest = mCurrentPkgResult.insertTest(test);
         }
     }
 
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/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 b74e26c..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,37 @@
                 "<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() {
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/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