Merge "Changed behaviour on main Activity relaunch to finish immediately for clockwork devices to accomodate clockwork's exit to the watchface on screen off." into lmp-sprout-dev
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 4964e60..d6d655a 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_r1">
 
     <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="21"/>
 
@@ -157,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"
@@ -239,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>
@@ -248,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"
@@ -338,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>
@@ -347,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>
@@ -358,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"
@@ -382,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>
@@ -391,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"
@@ -800,8 +813,14 @@
                 <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" />
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.stepdetector" />
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.proximity" />
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.light" />
         </activity>
 
         <!-- TODO: enable when a more reliable way to identify time synchronization is available -->
@@ -825,6 +844,14 @@
                 <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" />
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.compass" />
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.gyroscope" />
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.barometer" />
         </activity>
 
         <activity android:name=".sensors.SensorBatchingTestsActivity"
@@ -835,8 +862,14 @@
                 <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" />
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.compass" />
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.gyroscope" />
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.barometer" />
         </activity>
 
         <activity android:name=".sensors.SensorIntegrationTestsActivity"
@@ -847,6 +880,12 @@
                 <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" />
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.compass" />
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.gyroscope" />
         </activity>
 
         <activity android:name=".sensors.SensorTestActivity"
@@ -857,6 +896,18 @@
                 <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" />
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.stepcounter" />
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.stepdetector" />
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.heartrate" />
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.compass" />
+            <meta-data android:name="test_applicable_features"
+                       android:value="android.hardware.sensor.ambient_temperature" />
         </activity>
 
         <!-- End sensor tests definitions -->
@@ -868,6 +919,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">
@@ -878,6 +933,10 @@
             <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" />
+            <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">
@@ -887,6 +946,10 @@
             </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">
@@ -896,6 +959,10 @@
             </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" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.software.leanback" />
         </activity>
 
         <activity android:name=".camera.formats.CameraFormatsActivity"
@@ -1072,6 +1139,10 @@
             <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">
@@ -1082,6 +1153,10 @@
             <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"
@@ -1129,14 +1204,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">
@@ -1156,6 +1232,10 @@
                 <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 -->
@@ -1187,8 +1267,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">
@@ -1284,7 +1364,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>
@@ -1297,7 +1378,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>
@@ -1331,6 +1412,10 @@
                 <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">
@@ -1339,6 +1424,10 @@
                 <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">
@@ -1347,6 +1436,10 @@
                 <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"
diff --git a/apps/CtsVerifier/res/layout/ble_advertiser_hardware_scan_filter.xml b/apps/CtsVerifier/res/layout/ble_advertiser_hardware_scan_filter.xml
index ce3e1e1..a545727 100644
--- a/apps/CtsVerifier/res/layout/ble_advertiser_hardware_scan_filter.xml
+++ b/apps/CtsVerifier/res/layout/ble_advertiser_hardware_scan_filter.xml
@@ -19,63 +19,56 @@
         android:orientation="vertical"
         android:padding="10dip"
         >
-
-    <LinearLayout android:orientation="vertical"
+    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_centerInParent="true"
-            >
-        <TextView android:text="@string/ble_advertiser_scannable"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-        />
-        <TextView android:text="@string/ble_advertiser_scannable_instruction"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-        />
-        <LinearLayout android:orientation="horizontal"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                >
-            <Button android:id="@+id/ble_advertiser_scannable_start"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="@string/ble_advertiser_start"
-                    />
-            <Button android:id="@+id/ble_advertiser_scannable_stop"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="@string/ble_advertiser_stop"
-                    />
-        </LinearLayout>
-        <TextView android:text="@string/ble_advertiser_unscannable"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-        />
-        <TextView android:text="@string/ble_advertiser_unscannable_instruction"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-        />
-        <LinearLayout android:orientation="horizontal"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                >
-            <Button android:id="@+id/ble_advertiser_unscannable_start"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="@string/ble_advertiser_start"
-                    />
-            <Button android:id="@+id/ble_advertiser_unscannable_stop"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="@string/ble_advertiser_stop"
-                    />
-        </LinearLayout>
-    </LinearLayout>
+            android:scrollbars="vertical">
 
-    <include android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_alignParentBottom="true"
-            layout="@layout/pass_fail_buttons"
-            />
+        <LinearLayout android:orientation="vertical"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_centerInParent="true">
+            <TextView android:text="@string/ble_advertiser_scannable"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"/>
+            <TextView android:text="@string/ble_advertiser_scannable_instruction"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"/>
+            <LinearLayout android:orientation="horizontal"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content">
+                <Button android:id="@+id/ble_advertiser_scannable_start"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/ble_advertiser_start"/>
+                <Button android:id="@+id/ble_advertiser_scannable_stop"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/ble_advertiser_stop"/>
+            </LinearLayout>
+            <TextView android:text="@string/ble_advertiser_unscannable"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"/>
+            <TextView android:text="@string/ble_advertiser_unscannable_instruction"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"/>
+            <LinearLayout android:orientation="horizontal"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content">
+                <Button android:id="@+id/ble_advertiser_unscannable_start"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/ble_advertiser_start"/>
+                <Button android:id="@+id/ble_advertiser_unscannable_stop"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/ble_advertiser_stop"/>
+            </LinearLayout>
+
+            <include android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_alignParentBottom="true"
+                    layout="@layout/pass_fail_buttons"/>
+        </LinearLayout>
+    </ScrollView>
 </RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/ble_advertiser_power_level.xml b/apps/CtsVerifier/res/layout/ble_advertiser_power_level.xml
index ec3284d..c8e0133 100644
--- a/apps/CtsVerifier/res/layout/ble_advertiser_power_level.xml
+++ b/apps/CtsVerifier/res/layout/ble_advertiser_power_level.xml
@@ -19,31 +19,34 @@
         android:orientation="vertical"
         android:padding="10dip"
         >
-
-    <TextView android:text="@string/ble_advertiser_power_level_instruction"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-    />
-    <LinearLayout android:orientation="horizontal"
+    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content">
+        <LinearLayout android:orientation="vertical"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_centerInParent="true"
-            >
-        <Button android:id="@+id/ble_power_level_start"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/ble_advertiser_start"
-                />
-        <Button android:id="@+id/ble_power_level_stop"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/ble_advertiser_stop"
-                />
-    </LinearLayout>
+            android:layout_height="wrap_content">
+            <TextView android:text="@string/ble_advertiser_power_level_instruction"
+                    android:id="@+id/ble_advertiser_power_level_instruction"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:scrollbars="vertical"/>
+            <LinearLayout android:orientation="horizontal"
+                    android:layout_below="@+id/ble_advertiser_power_level_instruction"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content">
+                <Button android:id="@+id/ble_power_level_start"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/ble_advertiser_start"/>
+                <Button android:id="@+id/ble_power_level_stop"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/ble_advertiser_stop"/>
+            </LinearLayout>
 
-    <include android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_alignParentBottom="true"
-            layout="@layout/pass_fail_buttons"
-            />
+            <include android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    layout="@layout/pass_fail_buttons"/>
+        </LinearLayout>
+    </ScrollView>
 </RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/ble_client_connect.xml b/apps/CtsVerifier/res/layout/ble_client_connect.xml
index 54a0a99..30b4edb 100644
--- a/apps/CtsVerifier/res/layout/ble_client_connect.xml
+++ b/apps/CtsVerifier/res/layout/ble_client_connect.xml
@@ -20,22 +20,19 @@
         android:padding="10dip"
         >
 
-    <LinearLayout android:orientation="horizontal"
+    <LinearLayout android:orientation="vertical"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_centerInParent="true"
             >
-        <EditText android:id="@+id/ble_address"
-                android:layout_weight="1"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:hint="@string/ble_address"
-                />
-        <Button android:id="@+id/ble_connect"
+        <Button android:id="@+id/ble_scan_start"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:text="@string/ble_connect"
-                />
+                android:text="@string/ble_scan_start"/>
+        <Button android:id="@+id/ble_scan_stop"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/ble_scan_stop"/>
     </LinearLayout>
 
     <include android:layout_width="match_parent"
@@ -43,4 +40,4 @@
             android:layout_alignParentBottom="true"
             layout="@layout/pass_fail_buttons"
             />
-</RelativeLayout>
\ No newline at end of file
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/ble_client_read_write.xml b/apps/CtsVerifier/res/layout/ble_client_read_write.xml
index 7edba62..a263916 100644
--- a/apps/CtsVerifier/res/layout/ble_client_read_write.xml
+++ b/apps/CtsVerifier/res/layout/ble_client_read_write.xml
@@ -32,6 +32,7 @@
                     android:layout_width="0dp"
                     android:layout_weight="1"
                     android:layout_height="wrap_content"
+                    android:text="@string/ble_test_text"
                     android:hint="@string/ble_write_hint"
                     android:padding="10dip"
                     />
@@ -67,4 +68,4 @@
             android:layout_alignParentBottom="true"
             layout="@layout/pass_fail_buttons"
             />
-</RelativeLayout>
\ No newline at end of file
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/ble_reliable_write.xml b/apps/CtsVerifier/res/layout/ble_reliable_write.xml
index 7db78ff..05b1812 100644
--- a/apps/CtsVerifier/res/layout/ble_reliable_write.xml
+++ b/apps/CtsVerifier/res/layout/ble_reliable_write.xml
@@ -27,6 +27,7 @@
         <EditText android:id="@+id/write_text"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
+                android:text="@string/ble_test_text"
                 android:hint="@string/ble_write_hint"
                 android:padding="5dip"
                 />
@@ -60,4 +61,4 @@
             android:layout_alignParentBottom="true"
             layout="@layout/pass_fail_buttons"
             />
-</RelativeLayout>
\ No newline at end of file
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/ble_scanner_hardware_scan_filter.xml b/apps/CtsVerifier/res/layout/ble_scanner_hardware_scan_filter.xml
index f356ded..dabd640 100644
--- a/apps/CtsVerifier/res/layout/ble_scanner_hardware_scan_filter.xml
+++ b/apps/CtsVerifier/res/layout/ble_scanner_hardware_scan_filter.xml
@@ -17,40 +17,41 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:orientation="vertical"
-        android:padding="10dip"
-        >
-    <TextView android:text="@string/ble_scanner_scan_filter_instruction"
+        android:padding="10dip">
+    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-    />
-    <LinearLayout android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_centerInParent="true"
-            >
-        <LinearLayout android:orientation="horizontal"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                >
-            <Button android:id="@+id/ble_scan_with_filter"
+            android:layout_height="wrap_content">
+        <LinearLayout android:orientation="vertical"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content">
+            <TextView android:text="@string/ble_scanner_scan_filter_instruction"
                     android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"/>
+            <LinearLayout android:orientation="vertical"
+                    android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:text="@string/ble_scan_with_filter"
-                    />
-            <Button android:id="@+id/ble_scan_without_filter"
-                    android:layout_width="wrap_content"
+                    android:layout_centerInParent="true">
+                <LinearLayout android:orientation="vertical"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content">
+                    <Button android:id="@+id/ble_scan_with_filter"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:text="@string/ble_scan_with_filter"/>
+                    <Button android:id="@+id/ble_scan_without_filter"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:text="@string/ble_scan_without_filter"/>
+                </LinearLayout>
+                <ListView android:id="@+id/ble_scan_result_list"
+                        android:layout_height="wrap_content"
+                        android:layout_width="match_parent">
+                </ListView>
+            </LinearLayout>
+            <include android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:text="@string/ble_scan_without_filter"
-                    />
+                    android:layout_alignParentBottom="true"
+                    layout="@layout/pass_fail_buttons"/>
         </LinearLayout>
-        <ListView android:id="@+id/ble_scan_result_list"
-                android:layout_height="wrap_content"
-                android:layout_width="match_parent">
-        </ListView>
-    </LinearLayout>
-    <include android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_alignParentBottom="true"
-            layout="@layout/pass_fail_buttons"
-    />
+    </ScrollView>
 </RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/ble_scanner_power_level.xml b/apps/CtsVerifier/res/layout/ble_scanner_power_level.xml
index b240db6..c24dbb4 100644
--- a/apps/CtsVerifier/res/layout/ble_scanner_power_level.xml
+++ b/apps/CtsVerifier/res/layout/ble_scanner_power_level.xml
@@ -19,154 +19,139 @@
         android:orientation="vertical"
         android:padding="10dip"
         >
-    <TextView android:text="@string/ble_scanner_power_level_instruction"
+    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:id="@+id/ble_scanner_power_level_instruction"
-    />
-    <LinearLayout android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_below="@+id/ble_scanner_power_level_instruction"
-            android:layout_centerInParent="true"
-            android:padding="10dp"
-            >
-        <LinearLayout android:orientation="horizontal"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_centerInParent="true"
-                >
-            <TextView android:text="@string/ble_ultra_low"
-                  android:layout_width="100dp"
-                  android:layout_height="wrap_content"
-            />
-            <TextView android:id="@+id/ble_ultra_low_mac"
-                  android:layout_width="200dp"
-                  android:layout_height="wrap_content"
-            />
-            <TextView android:id="@+id/ble_ultra_low_rssi"
-                  android:layout_width="100dp"
-                  android:layout_height="wrap_content"
-            />
-        </LinearLayout>
-        <LinearLayout android:orientation="horizontal"
+            android:layout_height="wrap_content">
+        <LinearLayout android:orientation="vertical"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content">
-            <TextView android:layout_width="100dp"
-                  android:layout_height="wrap_content"/>
-            <TextView android:id="@+id/ble_ultra_low_count"
-                    android:layout_width="100dp"
+            <TextView android:text="@string/ble_scanner_power_level_instruction"
+                    android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
+                    android:id="@+id/ble_scanner_power_level_instruction"
             />
-            <TextView android:id="@+id/ble_ultra_low_set_power"
-                    android:layout_width="100dp"
+            <HorizontalScrollView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content">
+                <LinearLayout android:orientation="vertical"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_below="@+id/ble_scanner_power_level_instruction"
+                        android:layout_centerInParent="true"
+                        android:padding="10dp">
+                    <LinearLayout android:orientation="horizontal"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:layout_centerInParent="true">
+                        <TextView android:text="@string/ble_ultra_low"
+                                android:layout_width="100dp"
+                                android:layout_height="wrap_content"/>
+                        <TextView android:id="@+id/ble_ultra_low_mac"
+                                android:layout_width="200dp"
+                                android:layout_height="wrap_content"/>
+                        <TextView android:id="@+id/ble_ultra_low_rssi"
+                                android:layout_width="100dp"
+                                android:layout_height="wrap_content"/>
+                    </LinearLayout>
+                    <LinearLayout android:orientation="horizontal"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content">
+                        <TextView android:layout_width="100dp"
+                                android:layout_height="wrap_content"/>
+                        <TextView android:id="@+id/ble_ultra_low_count"
+                                android:layout_width="100dp"
+                                android:layout_height="wrap_content"/>
+                        <TextView android:id="@+id/ble_ultra_low_set_power"
+                                android:layout_width="100dp"
+                                android:layout_height="wrap_content"/>
+                    </LinearLayout>
+                    <LinearLayout android:orientation="horizontal"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:layout_centerInParent="true">
+                        <TextView android:text="@string/ble_low"
+                                android:layout_width="100dp"
+                                android:layout_height="wrap_content"/>
+                        <TextView android:id="@+id/ble_low_mac"
+                                android:layout_width="200dp"
+                                android:layout_height="wrap_content"/>
+                        <TextView android:id="@+id/ble_low_rssi"
+                                android:layout_width="100dp"
+                                android:layout_height="wrap_content"/>
+                    </LinearLayout>
+                    <LinearLayout android:orientation="horizontal"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content">
+                        <TextView android:layout_width="100dp"
+                                android:layout_height="wrap_content"/>
+                        <TextView android:id="@+id/ble_low_count"
+                                android:layout_width="100dp"
+                                android:layout_height="wrap_content"/>
+                        <TextView android:id="@+id/ble_low_set_power"
+                                android:layout_width="100dp"
+                                android:layout_height="wrap_content"/>
+                    </LinearLayout>
+                    <LinearLayout android:orientation="horizontal"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:layout_centerInParent="true">
+                        <TextView android:text="@string/ble_medium"
+                                android:layout_width="100dp"
+                                android:layout_height="wrap_content"/>
+                        <TextView android:id="@+id/ble_medium_mac"
+                                android:layout_width="200dp"
+                                android:layout_height="wrap_content"/>
+                        <TextView android:id="@+id/ble_medium_rssi"
+                                android:layout_width="100dp"
+                                android:layout_height="wrap_content"/>
+                    </LinearLayout>
+                    <LinearLayout android:orientation="horizontal"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content">
+                        <TextView android:layout_width="100dp"
+                                android:layout_height="wrap_content"/>
+                        <TextView android:id="@+id/ble_medium_count"
+                                android:layout_width="100dp"
+                                android:layout_height="wrap_content"/>
+                        <TextView android:id="@+id/ble_medium_set_power"
+                                android:layout_width="100dp"
+                                android:layout_height="wrap_content"/>
+                    </LinearLayout>
+                    <LinearLayout android:orientation="horizontal"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:layout_centerInParent="true">
+                        <TextView android:text="@string/ble_high"
+                                android:layout_width="100dp"
+                                android:layout_height="wrap_content"/>
+                        <TextView android:id="@+id/ble_high_mac"
+                                android:layout_width="200dp"
+                                android:layout_height="wrap_content"/>
+                        <TextView android:id="@+id/ble_high_rssi"
+                                android:layout_width="100dp"
+                                android:layout_height="wrap_content"/>
+                    </LinearLayout>
+                    <LinearLayout android:orientation="horizontal"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content">
+                        <TextView android:layout_width="100dp"
+                                android:layout_height="wrap_content"/>
+                        <TextView android:id="@+id/ble_high_count"
+                                android:layout_width="100dp"
+                                android:layout_height="wrap_content"/>
+                        <TextView android:id="@+id/ble_high_set_power"
+                                android:layout_width="100dp"
+                                android:layout_height="wrap_content"/>
+                    </LinearLayout>
+                </LinearLayout>
+            </HorizontalScrollView>
+            <TextView android:id="@+id/ble_timer"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" />
+            <include android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-            />
+                    android:layout_alignParentBottom="true"
+                    layout="@layout/pass_fail_buttons"/>
         </LinearLayout>
-        <LinearLayout android:orientation="horizontal"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_centerInParent="true"
-                >
-            <TextView android:text="@string/ble_low"
-                  android:layout_width="100dp"
-                  android:layout_height="wrap_content"
-            />
-            <TextView android:id="@+id/ble_low_mac"
-                  android:layout_width="200dp"
-                  android:layout_height="wrap_content"
-            />
-            <TextView android:id="@+id/ble_low_rssi"
-                  android:layout_width="100dp"
-                  android:layout_height="wrap_content"
-            />
-        </LinearLayout>
-        <LinearLayout android:orientation="horizontal"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content">
-            <TextView android:layout_width="100dp"
-                  android:layout_height="wrap_content"/>
-            <TextView android:id="@+id/ble_low_count"
-                    android:layout_width="100dp"
-                    android:layout_height="wrap_content"
-            />
-            <TextView android:id="@+id/ble_low_set_power"
-                    android:layout_width="100dp"
-                    android:layout_height="wrap_content"
-            />
-        </LinearLayout>
-        <LinearLayout android:orientation="horizontal"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_centerInParent="true"
-                >
-            <TextView android:text="@string/ble_medium"
-                  android:layout_width="100dp"
-                  android:layout_height="wrap_content"
-            />
-            <TextView android:id="@+id/ble_medium_mac"
-                  android:layout_width="200dp"
-                  android:layout_height="wrap_content"
-            />
-            <TextView android:id="@+id/ble_medium_rssi"
-                  android:layout_width="100dp"
-                  android:layout_height="wrap_content"
-            />
-        </LinearLayout>
-        <LinearLayout android:orientation="horizontal"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content">
-            <TextView android:layout_width="100dp"
-                  android:layout_height="wrap_content"/>
-            <TextView android:id="@+id/ble_medium_count"
-                    android:layout_width="100dp"
-                    android:layout_height="wrap_content"
-            />
-            <TextView android:id="@+id/ble_medium_set_power"
-                    android:layout_width="100dp"
-                    android:layout_height="wrap_content"
-            />
-        </LinearLayout>
-        <LinearLayout android:orientation="horizontal"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_centerInParent="true"
-                >
-            <TextView android:text="@string/ble_high"
-                  android:layout_width="100dp"
-                  android:layout_height="wrap_content"
-            />
-            <TextView android:id="@+id/ble_high_mac"
-                  android:layout_width="200dp"
-                  android:layout_height="wrap_content"
-            />
-            <TextView android:id="@+id/ble_high_rssi"
-                  android:layout_width="100dp"
-                  android:layout_height="wrap_content"
-            />
-        </LinearLayout>
-        <LinearLayout android:orientation="horizontal"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content">
-            <TextView android:layout_width="100dp"
-                  android:layout_height="wrap_content"/>
-            <TextView android:id="@+id/ble_high_count"
-                    android:layout_width="100dp"
-                    android:layout_height="wrap_content"
-            />
-            <TextView android:id="@+id/ble_high_set_power"
-                    android:layout_width="100dp"
-                    android:layout_height="wrap_content"
-            />
-        </LinearLayout>
-        <TextView android:id="@+id/ble_timer"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content" />
-    </LinearLayout>
-
-    <include android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_alignParentBottom="true"
-            layout="@layout/pass_fail_buttons"
-            />
+    </ScrollView>
 </RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/js_charging.xml b/apps/CtsVerifier/res/layout/js_charging.xml
index 4c0e552..5552111 100644
--- a/apps/CtsVerifier/res/layout/js_charging.xml
+++ b/apps/CtsVerifier/res/layout/js_charging.xml
@@ -1,67 +1,72 @@
 <?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"
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
     android:layout_height="match_parent">
-    <TextView
+    <LinearLayout
+        android:orientation="vertical"
         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"/>
+        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"
+        <LinearLayout
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:src="@drawable/fs_indeterminate"
-            android:layout_marginRight="@dimen/js_padding"/>
+            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:text="@string/js_charging_off_test"
-            android:textSize="16dp"/>
+            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>
-    <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
+</ScrollView>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/js_connectivity.xml b/apps/CtsVerifier/res/layout/js_connectivity.xml
index 5208c18..e0fc740 100644
--- a/apps/CtsVerifier/res/layout/js_connectivity.xml
+++ b/apps/CtsVerifier/res/layout/js_connectivity.xml
@@ -1,83 +1,86 @@
 <?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"
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    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"/>
+        android:orientation="vertical" android:layout_width="match_parent"
+        android:layout_height="match_parent">
         <TextView
-            android:layout_width="wrap_content"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:text="@string/js_unmetered_connectivity_test"
-            android:textSize="16dp"/>
-    </LinearLayout>
+            android:text="@string/js_test_description"
+            android:layout_margin="@dimen/js_padding"/>
 
-    <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_width="match_parent"
             android:layout_height="wrap_content"
-            android:text="@string/js_any_connectivity_test"
-            android:textSize="16dp"/>
-    </LinearLayout>
+            android:text="@string/js_connectivity_description_1"
+            android:layout_margin="@dimen/js_padding"
+            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/connectivity_off_test_no_connectivity_image"
+        <Button
+            android:id="@+id/js_connectivity_start_test_button"
             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>
+            android:layout_gravity="center"
+            android:text="@string/js_start_test_text"
+            android:onClick="startTest"
+            android:enabled="false"/>
 
-    <include layout="@layout/pass_fail_buttons" />
-</LinearLayout>
\ No newline at end of file
+        <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>
+</ScrollView>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/js_idle.xml b/apps/CtsVerifier/res/layout/js_idle.xml
index 90e55ec..453b638 100644
--- a/apps/CtsVerifier/res/layout/js_idle.xml
+++ b/apps/CtsVerifier/res/layout/js_idle.xml
@@ -1,63 +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"
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    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"/>
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
         <TextView
-            android:layout_width="wrap_content"
+            android:layout_width="match_parent"
             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"/>
+            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:text="@string/js_idle_item_idle_on"
-            android:textSize="16dp"/>
+            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>
-    <include layout="@layout/pass_fail_buttons" />
-</LinearLayout>
\ No newline at end of file
+</ScrollView>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 9d8287b..2f3d62f 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -214,6 +214,7 @@
     <string name="ble_waiting_notification">Waiting on notification</string>
     <string name="ble_read_rssi">Read RSSI</string>
     <string name="ble_disconnect">Disconnect</string>
+    <string name="ble_test_text">TEST</string>
 
     <!-- BLE server side strings -->
     <string name="ble_server_service_name">Bluetooth LE GATT Server Handler Service</string>
@@ -263,6 +264,8 @@
     <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>
+    <string name="ble_scan_start">Start scan</string>
+    <string name="ble_scan_stop">Stop scan</string>
 
     <!-- Strings for FeatureSummaryActivity -->
     <string name="feature_summary">Hardware/Software Feature Summary</string>
@@ -1288,7 +1291,7 @@
     <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 -->
@@ -1303,7 +1306,7 @@
 
     <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_description_1">Unplug the device 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>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java b/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
index 2d7d6ba..ebddf4f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
@@ -77,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>
  */
@@ -90,6 +97,8 @@
 
     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;
@@ -177,8 +186,9 @@
             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);
@@ -229,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);
@@ -282,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/BleClientConnectActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientConnectActivity.java
index fb351b1..4e1c268 100755
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientConnectActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientConnectActivity.java
@@ -45,22 +45,25 @@
                          R.string.ble_client_send_connect_info, -1);
         getPassButton().setEnabled(false);
 
-        mEditText = (EditText) findViewById(R.id.ble_address);
-
-        ((Button) findViewById(R.id.ble_connect)).setOnClickListener(new OnClickListener() {
+        ((Button) findViewById(R.id.ble_scan_start)).setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View v) {
-                String address = mEditText.getText().toString();
-                if (!BluetoothAdapter.checkBluetoothAddress(address)) {
-                    showMessage("Invalid bluetooth address.");
-                } else {
-                    Intent intent = new Intent(BleClientConnectActivity.this,
-                                               BleClientService.class);
-                    intent.putExtra(BleClientService.EXTRA_COMMAND,
-                                    BleClientService.COMMAND_CONNECT);
-                    intent.putExtra(BluetoothDevice.EXTRA_DEVICE, address);
-                    startService(intent);
-                }
+                Intent intent = new Intent(BleClientConnectActivity.this,
+                        BleClientService.class);
+                intent.putExtra(BleClientService.EXTRA_COMMAND,
+                        BleClientService.COMMAND_SCAN_START);
+                startService(intent);
+            }
+        });
+
+        ((Button) findViewById(R.id.ble_scan_stop)).setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(BleClientConnectActivity.this,
+                        BleClientService.class);
+                intent.putExtra(BleClientService.EXTRA_COMMAND,
+                        BleClientService.COMMAND_SCAN_STOP);
+                startService(intent);
             }
         });
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
index 556ad06..6765362 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
@@ -16,6 +16,7 @@
 
 package com.android.cts.verifier.bluetooth;
 
+import java.util.Arrays;
 import java.util.UUID;
 import java.util.List;
 
@@ -29,10 +30,16 @@
 import android.bluetooth.BluetoothGattService;
 import android.bluetooth.BluetoothManager;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanFilter;
+import android.bluetooth.le.ScanResult;
+import android.bluetooth.le.ScanSettings;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.ParcelUuid;
 import android.util.Log;
 import android.widget.Toast;
 
@@ -53,6 +60,8 @@
     public static final int COMMAND_BEGIN_WRITE = 9;
     public static final int COMMAND_EXECUTE_WRITE = 10;
     public static final int COMMAND_ABORT_RELIABLE = 11;
+    public static final int COMMAND_SCAN_START = 12;
+    public static final int COMMAND_SCAN_STOP = 13;
 
     public static final String BLE_BLUETOOTH_CONNECTED =
             "com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_CONNECTED";
@@ -102,6 +111,8 @@
     private BluetoothDevice mDevice;
     private BluetoothGatt mBluetoothGatt;
     private Handler mHandler;
+    private Context mContext;
+    private BluetoothLeScanner mScanner;
 
     @Override
     public void onCreate() {
@@ -110,6 +121,8 @@
         mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
         mBluetoothAdapter = mBluetoothManager.getAdapter();
         mHandler = new Handler();
+        mContext = this;
+        mScanner = mBluetoothAdapter.getBluetoothLeScanner();
     }
 
     @Override
@@ -128,6 +141,7 @@
         super.onDestroy();
         mBluetoothGatt.disconnect();
         mBluetoothGatt.close();
+        stopScan();
     }
 
     private void handleIntent(Intent intent) {
@@ -177,6 +191,12 @@
             case COMMAND_ABORT_RELIABLE:
                 if (mBluetoothGatt != null) mBluetoothGatt.abortReliableWrite(mDevice);
                 break;
+            case COMMAND_SCAN_START:
+                startScan();
+                break;
+            case COMMAND_SCAN_STOP:
+                stopScan();
+                break;
             default:
                 showMessage("Unrecognized command: " + command);
                 break;
@@ -343,8 +363,8 @@
         @Override
         public void onCharacteristicWrite(BluetoothGatt gatt,
                                           BluetoothGattCharacteristic characteristic, int status) {
-            if (DEBUG) Log.d(TAG, "onCharacteristicWrite: characteristic.val=" + characteristic.getStringValue(0)
-                                  + " status=" + status);
+            if (DEBUG) Log.d(TAG, "onCharacteristicWrite: characteristic.val="
+                    + characteristic.getStringValue(0) + " status=" + status);
             BluetoothGattCharacteristic mCharacteristic = getCharacteristic(CHARACTERISTIC_UUID);
             if ((status == BluetoothGatt.GATT_SUCCESS) &&
                 (characteristic.getStringValue(0).equals(mCharacteristic.getStringValue(0)))) {
@@ -387,4 +407,25 @@
             if (status == BluetoothGatt.GATT_SUCCESS) notifyReadRemoteRssi(rssi);
         }
     };
-}
\ No newline at end of file
+
+    private final ScanCallback mScanCallback = new ScanCallback() {
+        @Override
+        public void onScanResult(int callbackType, ScanResult result) {
+            mBluetoothGatt = result.getDevice().connectGatt(mContext, false, mGattCallbacks);
+        }
+    };
+
+    private void startScan() {
+        if (DEBUG) Log.d(TAG, "startScan");
+        List<ScanFilter> filter = Arrays.asList(new ScanFilter.Builder().setServiceUuid(
+                new ParcelUuid(BleServerService.ADV_SERVICE_UUID)).build());
+        ScanSettings setting = new ScanSettings.Builder()
+                .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER).build();
+        mScanner.startScan(filter, setting, mScanCallback);
+    }
+
+    private void stopScan() {
+        if (DEBUG) Log.d(TAG, "stopScan");
+        mScanner.stopScan(mScanCallback);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleReadWriteActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleReadWriteActivity.java
index 22233ef..8041ce0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleReadWriteActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleReadWriteActivity.java
@@ -124,4 +124,4 @@
             }
         }
     };
-}
\ No newline at end of file
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleReliableWriteActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleReliableWriteActivity.java
index c7460b5..9b65bb4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleReliableWriteActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleReliableWriteActivity.java
@@ -114,4 +114,4 @@
             }
         }
     };
-}
\ No newline at end of file
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java
index 91b3a6c..8718f57 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java
@@ -33,10 +33,15 @@
 import android.bluetooth.BluetoothGattService;
 import android.bluetooth.BluetoothManager;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.le.AdvertiseCallback;
+import android.bluetooth.le.AdvertiseData;
+import android.bluetooth.le.AdvertiseSettings;
+import android.bluetooth.le.BluetoothLeAdvertiser;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.ParcelUuid;
 import android.util.Log;
 import android.widget.Toast;
 
@@ -76,6 +81,8 @@
             UUID.fromString("00009997-0000-1000-8000-00805f9b34fb");
     private static final UUID DESCRIPTOR_UUID =
             UUID.fromString("00009996-0000-1000-8000-00805f9b34fb");
+    public static final UUID ADV_SERVICE_UUID=
+            UUID.fromString("00003333-0000-1000-8000-00805f9b34fb");
 
     private BluetoothManager mBluetoothManager;
     private BluetoothGattServer mGattServer;
@@ -84,12 +91,14 @@
     private Timer mNotificationTimer;
     private Handler mHandler;
     private String mReliableWriteValue;
+    private BluetoothLeAdvertiser mAdvertiser;
 
     @Override
     public void onCreate() {
         super.onCreate();
 
         mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
+        mAdvertiser = mBluetoothManager.getAdapter().getBluetoothLeAdvertiser();
         mGattServer = mBluetoothManager.openGattServer(this, mCallbacks);
         mService = createService();
         if (mGattServer != null) {
@@ -106,6 +115,7 @@
 
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
+        startAdvertise();
         return START_NOT_STICKY;
     }
 
@@ -117,6 +127,7 @@
     @Override
     public void onDestroy() {
         super.onDestroy();
+        stopAdvertise();
         if (mGattServer == null) {
            return;
         }
@@ -366,5 +377,26 @@
             }
         }
     };
+
+    private void startAdvertise() {
+        if (DEBUG) Log.d(TAG, "startAdvertise");
+        AdvertiseData data = new AdvertiseData.Builder()
+            .addServiceData(new ParcelUuid(ADV_SERVICE_UUID), new byte[]{1,2,3})
+            .addServiceUuid(new ParcelUuid(ADV_SERVICE_UUID))
+            .build();
+        AdvertiseSettings setting = new AdvertiseSettings.Builder()
+            .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
+            .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
+            .setConnectable(true)
+            .build();
+        mAdvertiser.startAdvertising(setting, data, mAdvertiseCallback);
+    }
+
+    private void stopAdvertise() {
+        if (DEBUG) Log.d(TAG, "stopAdvertise");
+        mAdvertiser.stopAdvertising(mAdvertiseCallback);
+    }
+
+    private final AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback(){};
 }
 
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 6d3e7dc..74a5317 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
@@ -219,7 +219,12 @@
             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.hardware.hdmi.cec", false),
+            new Feature("android.software.leanback_only", false),
+            new Feature("android.software.voice_recognizers", false),
     };
 
     @Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
index da823e8..6a9de44 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -69,7 +69,6 @@
     protected DevicePolicyManager mDevicePolicyManager;
 
     private TestItem mProfileOwnerInstalled;
-    private TestItem mDiskEncryptionTest;
     private TestItem mProfileVisibleTest;
     private TestItem mDeviceAdminVisibleTest;
     private TestItem mWorkAppVisibleTest;
@@ -155,13 +154,6 @@
             }
         };
 
-        mDiskEncryptionTest = new TestItem(this, R.string.provisioning_byod_diskencryption) {
-            @Override
-            public TestResult getPassFailState() {
-                return isDeviceEncrypted() ? TestResult.Passed : TestResult.Failed;
-            }
-        };
-
         mProfileVisibleTest = new TestItem(this, R.string.provisioning_byod_profile_visible,
                 R.string.provisioning_byod_profile_visible_instruction,
                 new Intent(Settings.ACTION_SETTINGS));
@@ -181,7 +173,6 @@
                 R.string.provisioning_byod_cross_profile_instruction,
                 chooser);
 
-        mTests.add(mDiskEncryptionTest);
         mTests.add(mProfileOwnerInstalled);
         mTests.add(mProfileVisibleTest);
         mTests.add(mDeviceAdminVisibleTest);
@@ -284,11 +275,6 @@
                 PackageManager.DONT_KILL_APP);
     }
 
-    private boolean isDeviceEncrypted() {
-        return mDevicePolicyManager.getStorageEncryptionStatus()
-                == DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
-    }
-
     private void showToast(int messageId) {
         String message = getString(messageId);
         Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
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/tests/signature/src/android/signature/cts/JDiffClassDescription.java b/tests/signature/src/android/signature/cts/JDiffClassDescription.java
index 7e36c1c..afcaa15 100644
--- a/tests/signature/src/android/signature/cts/JDiffClassDescription.java
+++ b/tests/signature/src/android/signature/cts/JDiffClassDescription.java
@@ -731,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(
diff --git a/tests/tests/app/src/android/app/cts/DialogTest.java b/tests/tests/app/src/android/app/cts/DialogTest.java
index 56e731b..6df2eee 100644
--- a/tests/tests/app/src/android/app/cts/DialogTest.java
+++ b/tests/tests/app/src/android/app/cts/DialogTest.java
@@ -393,25 +393,28 @@
         d.isOnTouchEventCalled = false;
         assertTrue(d.isShowing());
 
-        // Send a touch event outside the activity.  This time the dialog will be dismissed
-        // because closeOnTouchOutside is true.
-        d.setCanceledOnTouchOutside(true);
+        // Watch activities cover the entire screen, so there is no way to touch outside.
+        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+            // Send a touch event outside the activity.  This time the dialog will be dismissed
+            // because closeOnTouchOutside is true.
+            d.setCanceledOnTouchOutside(true);
 
-        touchMotionEvent = MotionEvent.obtain(now, now + 1, MotionEvent.ACTION_DOWN,
-                1, 100, 0);
-        mInstrumentation.sendPointerSync(touchMotionEvent);
+            touchMotionEvent = MotionEvent.obtain(now, now + 1, MotionEvent.ACTION_DOWN,
+                    1, 100, 0);
+            mInstrumentation.sendPointerSync(touchMotionEvent);
 
-        new PollingCheck(TEST_TIMEOUT) {
-            protected boolean check() {
-                return d.dispatchTouchEventResult;
-            }
-        }.run();
+            new PollingCheck(TEST_TIMEOUT) {
+                protected boolean check() {
+                    return d.dispatchTouchEventResult;
+                }
+            }.run();
 
-        assertMotionEventEquals(touchMotionEvent, d.touchEvent);
+            assertMotionEventEquals(touchMotionEvent, d.touchEvent);
 
-        assertTrue(d.isOnTouchEventCalled);
-        assertMotionEventEquals(touchMotionEvent, d.onTouchEvent);
-        assertFalse(d.isShowing());
+            assertTrue(d.isOnTouchEventCalled);
+            assertMotionEventEquals(touchMotionEvent, d.onTouchEvent);
+            assertFalse(d.isShowing());
+        }
     }
 
     public void testTrackballEvent() {
diff --git a/tests/tests/display/src/android/display/cts/VirtualDisplayTest.java b/tests/tests/display/src/android/display/cts/VirtualDisplayTest.java
index f2f859a..872de91 100644
--- a/tests/tests/display/src/android/display/cts/VirtualDisplayTest.java
+++ b/tests/tests/display/src/android/display/cts/VirtualDisplayTest.java
@@ -57,7 +57,7 @@
     private static final int WIDTH = 720;
     private static final int HEIGHT = 480;
     private static final int DENSITY = DisplayMetrics.DENSITY_MEDIUM;
-    private static final int TIMEOUT = 10000;
+    private static final int TIMEOUT = 40000;
 
     // Colors that we use as a signal to determine whether some desired content was
     // drawn.  The colors themselves doesn't matter but we choose them to have with distinct
diff --git a/tests/tests/hardware/AndroidManifest.xml b/tests/tests/hardware/AndroidManifest.xml
index ca148f9..1a02d0a 100644
--- a/tests/tests/hardware/AndroidManifest.xml
+++ b/tests/tests/hardware/AndroidManifest.xml
@@ -23,6 +23,7 @@
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.BODY_SENSORS" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
index 5346ae1..ec2f95b 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
@@ -326,7 +326,13 @@
                 flashTestByAeMode(listener, CaptureRequest.CONTROL_AE_MODE_ON);
 
                 // LEGACY won't support AE mode OFF
-                if (mStaticInfo.isHardwareLevelLimitedOrBetter()) {
+                boolean aeOffModeSupported = false;
+                for (int aeMode : mStaticInfo.getAeAvailableModesChecked()) {
+                    if (aeMode == CaptureRequest.CONTROL_AE_MODE_OFF) {
+                        aeOffModeSupported = true;
+                    }
+                }
+                if (aeOffModeSupported) {
                     flashTestByAeMode(listener, CaptureRequest.CONTROL_AE_MODE_OFF);
                 }
 
diff --git a/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java b/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
index 5c9f1b1..dbe2c92 100644
--- a/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
+++ b/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
@@ -19,6 +19,7 @@
 import com.android.cts.media.R;
 
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.content.res.AssetFileDescriptor;
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
@@ -285,6 +286,11 @@
     }
 
     private void ex(Iterable<Codec> codecList, Test[] testList) {
+        if (codecList == null) {
+            Log.i(TAG, "CodecList was empty. Skipping test.");
+            return;
+        }
+
         TestList tests = new TestList();
         for (Codec c : codecList) {
             for (Test test : testList) {
@@ -1342,8 +1348,21 @@
 }
 
 class CodecFactory {
+    protected boolean hasCodec(String codecName) {
+        MediaCodecList list = new MediaCodecList(MediaCodecList.ALL_CODECS);
+        for (MediaCodecInfo info : list.getCodecInfos()) {
+            if (codecName.equals(info.getName())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     public CodecList createCodecList(
             Context context, String mime, String googleCodecName, int ...resources) {
+        if (!hasCodec(googleCodecName)) {
+            return null;
+        }
         return new CodecFamily(context, mime, googleCodecName, resources);
     }
 }
@@ -1351,6 +1370,9 @@
 class SWCodecFactory extends CodecFactory {
     public CodecList createCodecList(
             Context context, String mime, String googleCodecName, int ...resources) {
+        if (!hasCodec(googleCodecName)) {
+            return null;
+        }
         return new CodecByName(context, mime, googleCodecName, resources);
     }
 }
@@ -1358,6 +1380,9 @@
 class HWCodecFactory extends CodecFactory {
     public CodecList createCodecList(
             Context context, String mime, String googleCodecName, int ...resources) {
+        if (!hasCodec(googleCodecName)) {
+            return null;
+        }
         return new CodecFamilyExcept(context, mime, googleCodecName, resources);
     }
 }
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackTest.java b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
index d01ecec..a342c37 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrackTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
@@ -16,6 +16,7 @@
 
 package android.media.cts;
 
+import android.content.pm.PackageManager;
 import android.cts.util.CtsAndroidTestCase;
 import android.media.AudioFormat;
 import android.media.AudioManager;
@@ -1541,7 +1542,16 @@
         }
     }
 
+    private boolean hasAudioOutput() {
+        return getContext().getPackageManager()
+            .hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT);
+    }
+
     public void testGetTimestamp() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
+        
         // constants for test
         final String TEST_NAME = "testGetTimestamp";
         final int TEST_SR = 22050;
diff --git a/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java b/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java
index c05a605..673c1d7 100644
--- a/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java
+++ b/tests/tests/media/src/android/media/cts/ClearKeySystemTest.java
@@ -16,6 +16,7 @@
 package android.media.cts;
 
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
 import android.media.MediaCodecInfo.CodecCapabilities;
@@ -402,10 +403,19 @@
         }
     }
 
+    private boolean hasAudioOutput() {
+        return getInstrumentation().getTargetContext().getPackageManager()
+            .hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT);
+    }
+
     /**
      * Tests clear key system playback.
      */
     public void testClearKeyPlayback() throws Exception {
+        if (!hasAudioOutput()) {
+            return;
+        }
+        
         MediaDrm drm = startDrm();
         if (null == drm) {
             throw new Error("Failed to create drm.");
diff --git a/tests/tests/media/src/android/media/cts/DecoderTest.java b/tests/tests/media/src/android/media/cts/DecoderTest.java
index ba70f32..8917144 100644
--- a/tests/tests/media/src/android/media/cts/DecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTest.java
@@ -24,6 +24,7 @@
 import android.media.Image;
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
+import android.media.MediaCodecList;
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
 import android.util.Log;
@@ -78,6 +79,42 @@
         masterFd.close();
     }
 
+    private boolean hasCodecForMimeType(String mimeType) {
+        MediaCodecList list = new MediaCodecList(MediaCodecList.ALL_CODECS);
+        for (MediaCodecInfo info : list.getCodecInfos()) {
+            for (String type : info.getSupportedTypes()) {
+                if (type.equalsIgnoreCase(mimeType)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private boolean hasH264() {
+        return hasCodecForMimeType("video/avc");
+    }
+
+    private boolean hasHEVC() {
+        return hasCodecForMimeType("video/hevc");
+    }
+
+    private boolean hasH263() {
+        return hasCodecForMimeType("video/3gpp");
+    }
+
+    private boolean hasMpeg4() {
+        return hasCodecForMimeType("video/mp4v-es");
+    }
+
+    private boolean hasVP8() {
+        return hasCodecForMimeType("video/x-vnd.on2.vp8");
+    }
+
+    private boolean hasVP9() {
+        return hasCodecForMimeType("video/x-vnd.on2.vp9");
+    }
+
     // TODO: add similar tests for other audio and video formats
     public void testBug11696552() throws Exception {
         MediaCodec mMediaCodec = MediaCodec.createDecoderByType("audio/mp4a-latm");
@@ -175,6 +212,10 @@
         MediaFormat format = ex.getTrackFormat(0);
         String mime = format.getString(MediaFormat.KEY_MIME);
         assertTrue("not a video track. Wrong test file?", mime.startsWith("video/"));
+        if (!hasCodecForMimeType(mime)) {
+            Log.i(TAG, "Could not find a codec for mimeType: " + mime);
+            return;
+        }
         MediaCodec dec = MediaCodec.createDecoderByType(mime);
         Surface s = getActivity().getSurfaceHolder().getSurface();
         dec.configure(format, s, null, 0);
@@ -840,6 +881,9 @@
     }
 
     public void testCodecBasicH264() throws Exception {
+        if (!hasH264()) {
+            return;
+        }
         Surface s = getActivity().getSurfaceHolder().getSurface();
         int frames1 = countFrames(
                 R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz,
@@ -853,6 +897,9 @@
     }
 
     public void testCodecBasicHEVC() throws Exception {
+        if (!hasHEVC()) {
+            return;
+        }
         Surface s = getActivity().getSurfaceHolder().getSurface();
         int frames1 = countFrames(
                 R.raw.video_1280x720_mp4_hevc_1150kbps_30fps_aac_stereo_128kbps_48000hz,
@@ -866,6 +913,9 @@
     }
 
     public void testCodecBasicH263() throws Exception {
+        if (!hasH263()) {
+            return;
+        }
         Surface s = getActivity().getSurfaceHolder().getSurface();
         int frames1 = countFrames(
                 R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz,
@@ -879,6 +929,9 @@
     }
 
     public void testCodecBasicMpeg4() throws Exception {
+        if (!hasMpeg4()) {
+            return;
+        }
         Surface s = getActivity().getSurfaceHolder().getSurface();
         int frames1 = countFrames(
                 R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz,
@@ -892,6 +945,9 @@
     }
 
     public void testCodecBasicVP8() throws Exception {
+        if (!hasVP8()) {
+            return;
+        }
         Surface s = getActivity().getSurfaceHolder().getSurface();
         int frames1 = countFrames(
                 R.raw.video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz,
@@ -905,6 +961,9 @@
     }
 
     public void testCodecBasicVP9() throws Exception {
+        if (!hasVP9()) {
+            return;
+        }
         Surface s = getActivity().getSurfaceHolder().getSurface();
         int frames1 = countFrames(
                 R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_44100hz,
@@ -918,6 +977,9 @@
     }
 
     public void testCodecEarlyEOSH263() throws Exception {
+        if (!hasH263()) {
+            return;
+        }
         Surface s = getActivity().getSurfaceHolder().getSurface();
         int frames1 = countFrames(
                 R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz,
@@ -926,6 +988,9 @@
     }
 
     public void testCodecEarlyEOSH264() throws Exception {
+        if (!hasH264()) {
+            return;
+        }
         Surface s = getActivity().getSurfaceHolder().getSurface();
         int frames1 = countFrames(
                 R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz,
@@ -934,6 +999,9 @@
     }
 
     public void testCodecEarlyEOSHEVC() throws Exception {
+        if (!hasHEVC()) {
+            return;
+        }
         Surface s = getActivity().getSurfaceHolder().getSurface();
         int frames1 = countFrames(
                 R.raw.video_1280x720_mp4_hevc_1150kbps_30fps_aac_stereo_128kbps_48000hz,
@@ -942,6 +1010,9 @@
     }
 
     public void testCodecEarlyEOSMpeg4() throws Exception {
+        if (!hasMpeg4()) {
+            return;
+        }
         Surface s = getActivity().getSurfaceHolder().getSurface();
         int frames1 = countFrames(
                 R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz,
@@ -950,6 +1021,9 @@
     }
 
     public void testCodecEarlyEOSVP8() throws Exception {
+        if (!hasVP8()) {
+            return;
+        }
         Surface s = getActivity().getSurfaceHolder().getSurface();
         int frames1 = countFrames(
                 R.raw.video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz,
@@ -958,6 +1032,9 @@
     }
 
     public void testCodecEarlyEOSVP9() throws Exception {
+        if (!hasVP9()) {
+            return;
+        }
         Surface s = getActivity().getSurfaceHolder().getSurface();
         int frames1 = countFrames(
                 R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_44100hz,
@@ -966,66 +1043,102 @@
     }
 
     public void testCodecResetsH264WithoutSurface() throws Exception {
+        if (!hasH264()) {
+            return;
+        }
         testCodecResets(
                 R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz, null);
     }
 
     public void testCodecResetsH264WithSurface() throws Exception {
+        if (!hasH264()) {
+            return;
+        }
         Surface s = getActivity().getSurfaceHolder().getSurface();
         testCodecResets(
                 R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz, s);
     }
 
     public void testCodecResetsHEVCWithoutSurface() throws Exception {
+        if (!hasHEVC()) {
+            return;
+        }
         testCodecResets(
                 R.raw.video_1280x720_mp4_hevc_1150kbps_30fps_aac_stereo_128kbps_48000hz, null);
     }
 
     public void testCodecResetsHEVCWithSurface() throws Exception {
+        if (!hasHEVC()) {
+            return;
+        }
         Surface s = getActivity().getSurfaceHolder().getSurface();
         testCodecResets(
                 R.raw.video_1280x720_mp4_hevc_1150kbps_30fps_aac_stereo_128kbps_48000hz, s);
     }
 
     public void testCodecResetsH263WithoutSurface() throws Exception {
+        if (!hasH263()) {
+            return;
+        }
         testCodecResets(
                 R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz, null);
     }
 
     public void testCodecResetsH263WithSurface() throws Exception {
+        if (!hasH263()) {
+            return;
+        }
         Surface s = getActivity().getSurfaceHolder().getSurface();
         testCodecResets(
                 R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz, s);
     }
 
     public void testCodecResetsMpeg4WithoutSurface() throws Exception {
+        if (!hasMpeg4()) {
+            return;
+        }
         testCodecResets(
                 R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz, null);
     }
 
     public void testCodecResetsMpeg4WithSurface() throws Exception {
+        if (!hasMpeg4()) {
+            return;
+        }
         Surface s = getActivity().getSurfaceHolder().getSurface();
         testCodecResets(
                 R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz, s);
     }
 
     public void testCodecResetsVP8WithoutSurface() throws Exception {
+        if (!hasVP8()) {
+            return;
+        }
         testCodecResets(
                 R.raw.video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz, null);
     }
 
     public void testCodecResetsVP8WithSurface() throws Exception {
+        if (!hasVP8()) {
+            return;
+        }
         Surface s = getActivity().getSurfaceHolder().getSurface();
         testCodecResets(
                 R.raw.video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz, s);
     }
 
     public void testCodecResetsVP9WithoutSurface() throws Exception {
+        if (!hasVP9()) {
+            return;
+        }
         testCodecResets(
                 R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_44100hz, null);
     }
 
     public void testCodecResetsVP9WithSurface() throws Exception {
+        if (!hasVP9()) {
+            return;
+        }
         Surface s = getActivity().getSurfaceHolder().getSurface();
         testCodecResets(
                 R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_44100hz, s);
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
index 08e6212..723652f 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
@@ -15,6 +15,7 @@
  */
 package android.media.cts;
 
+import android.content.pm.PackageManager;
 import android.media.MediaCodecInfo;
 import android.media.MediaCodecInfo.CodecCapabilities;
 import android.media.MediaCodecInfo.CodecProfileLevel;
@@ -36,10 +37,7 @@
     private static final int PLAY_TIME_MS = 30000;
 
     public void testAvcBaseline1() throws Exception {
-        if (!supports(AVC_MIME, CodecProfileLevel.AVCProfileBaseline)) {
-          return;
-        }
-        if (!supports(AVC_MIME, CodecProfileLevel.AVCProfileBaseline,
+        if (hasCodec(AVC_MIME) && !supports(AVC_MIME, CodecProfileLevel.AVCProfileBaseline,
                 CodecProfileLevel.AVCLevel1)) {
             throw new RuntimeException("AVCLevel1 support is required by CDD");
         }
@@ -125,7 +123,7 @@
     }
 
     public void testHevcMain1() throws Exception {
-        if (!supports(HEVC_MIME, CodecProfileLevel.HEVCProfileMain,
+        if (hasCodec(HEVC_MIME) && !supports(HEVC_MIME, CodecProfileLevel.HEVCProfileMain,
                 CodecProfileLevel.HEVCMainTierLevel1)) {
             throw new RuntimeException("HECLevel1 support is required by CDD");
         }
@@ -238,4 +236,15 @@
         return false;
     }
 
+    private static boolean hasCodec(String mimeType) {
+        MediaCodecList list = new MediaCodecList(MediaCodecList.ALL_CODECS);
+        for (MediaCodecInfo info : list.getCodecInfos()) {
+            for (String type : info.getSupportedTypes()) {
+                if (type.equalsIgnoreCase(mimeType)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
 }
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecTest.java b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
index f72e3a0..5f8885d 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
@@ -79,11 +79,17 @@
      * methods when called in incorrect operational states.
      */
     public void testException() throws Exception {
+        String mimeType = "audio/amr-wb";
+        if (!supportsCodec(mimeType, false)) {
+            Log.i(TAG, "No decoder found for mimeType= " + mimeType);
+            return;
+        }
+
         MediaFormat[] formatList = new MediaFormat[2];
 
         // use audio format
         formatList[0] = new MediaFormat();
-        formatList[0].setString(MediaFormat.KEY_MIME, "audio/amr-wb");
+        formatList[0].setString(MediaFormat.KEY_MIME, mimeType);
         formatList[0].setInteger(MediaFormat.KEY_SAMPLE_RATE, 16000);
         formatList[0].setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
         formatList[0].setInteger(MediaFormat.KEY_BIT_RATE, 19850);
@@ -272,6 +278,11 @@
      * <br> calling createInputSurface() with a non-Surface color format throws exception
      */
     public void testCreateInputSurfaceErrors() {
+        if (!supportsCodec(MIME_TYPE, true)) {
+            Log.i(TAG, "No encoder found for mimeType= " + MIME_TYPE);
+            return;
+        }
+
         MediaFormat format = createMediaFormat();
         MediaCodec encoder = null;
         Surface surface = null;
@@ -326,6 +337,11 @@
      * <br> submitting a frame after EOS throws exception [TODO]
      */
     public void testSignalSurfaceEOS() {
+        if (!supportsCodec(MIME_TYPE, true)) {
+            Log.i(TAG, "No encoder found for mimeType= " + MIME_TYPE);
+            return;
+        }
+
         MediaFormat format = createMediaFormat();
         MediaCodec encoder = null;
         InputSurface inputSurface = null;
@@ -378,6 +394,11 @@
      * <br> stopping with buffers in flight doesn't crash or hang
      */
     public void testAbruptStop() {
+        if (!supportsCodec(MIME_TYPE, true)) {
+            Log.i(TAG, "No encoder found for mimeType= " + MIME_TYPE);
+            return;
+        }
+
         // There appears to be a race, so run it several times with a short delay between runs
         // to allow any previous activity to shut down.
         for (int i = 0; i < 50; i++) {
@@ -432,6 +453,11 @@
      * <br> dequeueInputBuffer() fails when encoder configured with an input Surface
      */
     public void testDequeueSurface() {
+        if (!supportsCodec(MIME_TYPE, true)) {
+            Log.i(TAG, "No encoder found for mimeType= " + MIME_TYPE);
+            return;
+        }
+
         MediaFormat format = createMediaFormat();
         MediaCodec encoder = null;
         Surface surface = null;
@@ -470,6 +496,11 @@
      * <br> sending EOS with signalEndOfInputStream on non-Surface encoder fails
      */
     public void testReconfigureWithoutSurface() {
+        if (!supportsCodec(MIME_TYPE, true)) {
+            Log.i(TAG, "No encoder found for mimeType= " + MIME_TYPE);
+            return;
+        }
+
         MediaFormat format = createMediaFormat();
         MediaCodec encoder = null;
         Surface surface = null;
@@ -553,8 +584,13 @@
             mediaExtractor = getMediaExtractorForMimeType(inputResourceId, "video/");
             MediaFormat mediaFormat =
                     mediaExtractor.getTrackFormat(mediaExtractor.getSampleTrackIndex());
+            String mimeType = mediaFormat.getString(MediaFormat.KEY_MIME);
+            if (!supportsCodec(mimeType, false)) {
+                Log.i(TAG, "No decoder found for mimeType= " + MIME_TYPE);
+                return true;
+            }
             mediaCodec =
-                    MediaCodec.createDecoderByType(mediaFormat.getString(MediaFormat.KEY_MIME));
+                    MediaCodec.createDecoderByType(mimeType);
             mediaCodec.configure(mediaFormat, outputSurface.getSurface(), null, 0);
             mediaCodec.start();
             boolean eos = false;
@@ -669,6 +705,16 @@
      * Tests creating an encoder and decoder for {@link #MIME_TYPE_AUDIO} at the same time.
      */
     public void testCreateAudioDecoderAndEncoder() {
+        if (!supportsCodec(MIME_TYPE_AUDIO, true)) {
+            Log.i(TAG, "No encoder found for mimeType= " + MIME_TYPE_AUDIO);
+            return;
+        }
+
+        if (!supportsCodec(MIME_TYPE_AUDIO, false)) {
+            Log.i(TAG, "No decoder found for mimeType= " + MIME_TYPE_AUDIO);
+            return;
+        }
+
         final MediaFormat encoderFormat = MediaFormat.createAudioFormat(
                 MIME_TYPE_AUDIO, AUDIO_SAMPLE_RATE, AUDIO_CHANNEL_COUNT);
         encoderFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, AUDIO_AAC_PROFILE);
@@ -716,6 +762,16 @@
     }
 
     public void testConcurrentAudioVideoEncodings() throws InterruptedException {
+        if (!supportsCodec(MIME_TYPE_AUDIO, true)) {
+            Log.i(TAG, "No encoder found for mimeType= " + MIME_TYPE_AUDIO);
+            return;
+        }
+
+        if (!supportsCodec(MIME_TYPE, true)) {
+            Log.i(TAG, "No decoder found for mimeType= " + MIME_TYPE);
+            return;
+        }
+
         final int VIDEO_NUM_SWAPS = 100;
         // audio only checks this and stop
         mVideoEncodingOngoing = true;
@@ -1006,4 +1062,23 @@
 
         return mediaExtractor;
     }
-}
+
+    private static boolean supportsCodec(String mimeType, boolean encoder) {
+        MediaCodecList list = new MediaCodecList(MediaCodecList.ALL_CODECS);
+        for (MediaCodecInfo info : list.getCodecInfos()) {
+            if (encoder && !info.isEncoder()) {
+                continue;
+            }
+            if (!encoder && info.isEncoder()) {
+                continue;
+            }
+            
+            for (String type : info.getSupportedTypes()) {
+                if (type.equalsIgnoreCase(mimeType)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+}
\ No newline at end of file
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 08e9a0b..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,10 +27,13 @@
 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.FileUtil;
@@ -54,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";
@@ -89,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;
@@ -104,6 +113,11 @@
         mReportDir = reportDir;
     }
 
+    /** Set whether to include TestLog tags in the XML reports. */
+    public void setIncludeTestLogTags(boolean include) {
+        mIncludeTestLogTags = include;
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -211,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.
@@ -219,6 +247,10 @@
         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) {
@@ -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 088bc8e..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
@@ -64,7 +64,6 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.Queue;
 import java.util.Set;
 
 
@@ -205,11 +204,10 @@
         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() {
@@ -324,7 +322,7 @@
     }
 
     /**
-     * Create a new {@link CtsTest} that will run the given {@List} of {@link TestPackage}s.
+     * 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) {
@@ -448,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;
@@ -468,6 +464,7 @@
         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);
@@ -482,14 +479,12 @@
         }
 
         // Setup the a map of Test id to ResultFilter
-        Map<String, ResultFilter> filterMap = new HashMap<String, ResultFilter>();
+        Map<String, ResultFilter> filterMap = new HashMap<>();
         int totalTestCount = 0;
         for (TestPackage testPackage : mTestPackageList) {
-            if (testPackage.getKnownTests().size() > 0) {
-                ResultFilter resultFilter = new ResultFilter(listener, testPackage);
-                totalTestCount += resultFilter.getKnownTestCount();
-                filterMap.put(testPackage.getPackageDef().getId(), resultFilter);
-            }
+            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
@@ -520,10 +515,6 @@
                         prerequisiteApks.get(currentAbi.getName()), currentAbi);
                 }
 
-                if (testPackage.getKnownTests().size() == 0) {
-                    // Skip empty packages. For example, those created by derived plans.
-                    continue;
-                }
                 IRemoteTest test = testPackage.getTestForPackage();
                 if (test instanceof IBuildReceiver) {
                     ((IBuildReceiver) test).setBuild(mBuildInfo);
@@ -571,19 +562,20 @@
     }
 
     /**
-     * @param packages The package list to filter
-     * @param abis The ABIs to test on
-     * @return A list of {@link TestPackage} which test one of the given ABIs
+     * @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<TestPackage> filterTestPackagesByAbi(
-            List<TestPackage> packages, Set<String> abis) {
-        List<TestPackage> testPackages = new LinkedList<>();
-        for (TestPackage test : packages) {
-            if (abis.contains(test.getAbi().getName())) {
-                testPackages.add(test);
+    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 testPackages;
+        return filteredTestPackageDefList;
     }
 
     /** Reboot then the device iff the list of packages exceeds the minimum */
@@ -593,7 +585,7 @@
             return;
         }
 
-        Set<String> packageNameSet = new HashSet<String>();
+        Set<String> packageNameSet = new HashSet<>();
         for (TestPackage testPackage : testPackageList) {
             // Parse the package name
             packageNameSet.add(AbiUtils.parseTestName(testPackage.getPackageDef().getId()));
@@ -688,84 +680,85 @@
             Log.logAndDisplay(LogLevel.INFO, LOG_TAG, "Resume tests using existing package list");
             return;
         }
-        Log.logAndDisplay(LogLevel.INFO, LOG_TAG, "ABIs: " + abis);
-
-        List<TestPackage> testPkgList = new ArrayList<TestPackage>();
         try {
             // Collect ALL tests
             ITestPackageRepo testRepo = createTestCaseRepo();
-            List<ITestPackageDef> testPkgDefs = new ArrayList<>(getTestPackagesToRun(testRepo, abis));
-            // Sort testPkgDefs. Note: run() relies on the fact that the list is reliably sorted for
-            // sharding purposes
+            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);
-            ITestPackageDef[] testPackageDefArray =
-                    testPkgDefs.toArray(new ITestPackageDef[testPkgDefs.size()]);
-            int totalShards = Math.min(mTotalShards, testPkgDefs.size());
-
-            for (int i = mShardAssignment; i < testPkgDefs.size(); i += totalShards) {
-                ITestPackageDef testPackageDef = testPackageDefArray[i];
+            // 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 (testForPackage != null) {
-                    testPkgList.add(
-                        new TestPackage(testPackageDef, testForPackage, testPackageDef.getTests()));
+                if (testPackageDef.getTests().size() > 0) {
+                    testPackageList.add(new TestPackage(testPackageDef, testForPackage));
                 }
             }
-            mTestPackageList.addAll(filterTestPackagesByAbi(testPkgList, abis));
+
+            // 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 the list of test package defs to run
+     * Return the {@link Set} of {@link ITestPackageDef}s to run unfiltered by ABI
      *
-     * @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 Set<ITestPackageDef> getTestPackagesToRun(
-            ITestPackageRepo testRepo, Set<String> abiSet)
+    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);
             plan.parse(createXmlStream(ctsPlanFile));
 
-            for (String packageName : plan.getTestNames()) {
-                if (mExcludedPackageNames.contains(packageName)) {
+            for (String testId : plan.getTestIds()) {
+                if (mExcludedPackageNames.contains(AbiUtils.parseTestName(testId))) {
                     continue;
                 }
-                Set<ITestPackageDef> testPackageDefSet = testRepo.getTestPackages(packageName);
-                if (testPackageDefSet.isEmpty()) {
-                    CLog.e("Could not find test package %s referenced in plan %s", packageName,
-                            mPlanName);
+                ITestPackageDef testPackageDef = testRepo.getTestPackage(testId);
+                if (testPackageDef == null) {
+                    CLog.e("Could not find test id %s referenced in plan %s", testId, mPlanName);
+                    continue;
                 }
-                for (ITestPackageDef testPackageDef : testPackageDefSet) {
-                    if (abiSet.contains(testPackageDef.getAbi().getName())) {
-                        testPackageDef.setTestFilter(plan.getTestFilter(testPackageDef.getId()));
-                        testPkgDefs.add(testPackageDef);
-                    }
-                }
+
+                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));
@@ -788,21 +781,18 @@
             PlanCreator planCreator = new PlanCreator(uniquePlanName, mContinueSessionId,
                     CtsTestStatus.NOT_EXECUTED);
             ITestPlan plan = createPlan(planCreator);
-            for (String packageName : plan.getTestNames()) {
-                if (mExcludedPackageNames.contains(packageName)) {
+            for (String testId : plan.getTestIds()) {
+                if (mExcludedPackageNames.contains(AbiUtils.parseTestName(testId))) {
                     continue;
                 }
-                Set<ITestPackageDef> testPackageDefSet = testRepo.getTestPackages(packageName);
-                if (testPackageDefSet.isEmpty()) {
-                    CLog.e("Could not find test package %s referenced in plan %s", packageName,
-                            mPlanName);
+                ITestPackageDef testPackageDef = testRepo.getTestPackage(testId);
+                if (testPackageDef == null) {
+                    CLog.e("Could not find test id %s referenced in plan %s", testId, mPlanName);
+                    continue;
                 }
-                for (ITestPackageDef testPackageDef : testPackageDefSet) {
-                    if (abiSet.contains(testPackageDef.getAbi().getName())) {
-                        testPackageDef.setTestFilter(plan.getTestFilter(testPackageDef.getId()));
-                        testPkgDefs.add(testPackageDef);
-                    }
-                }
+
+                testPackageDef.setTestFilter(plan.getTestFilter(testId));
+                testPkgDefs.add(testPackageDef);
             }
         } else {
             // should never get here - was checkFields() not called?
@@ -813,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) {
@@ -827,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()) {
@@ -851,7 +842,8 @@
 
     /**
      * Return the list (by abi) of unique prerequisite apks to install
-     * @param testPackages
+     *
+     * @param testPackages The {@link List} of {@link TestPackage} that contain prerequisite APKs
      */
     private Map<String, Set<String>> getPrerequisiteApks(
             List<TestPackage> testPackages, Set<String> abiSet) {
@@ -884,7 +876,7 @@
      *
      * 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, IAbi abi)
@@ -910,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 {
@@ -929,7 +921,7 @@
         }
         checkFields();
 
-        List<IRemoteTest> shardQueue = new LinkedList<IRemoteTest>();
+        List<IRemoteTest> shardQueue = new LinkedList<>();
         for (int shardAssignment = 0; shardAssignment < mShards; shardAssignment++) {
             CtsTest ctsTest = new CtsTest(shardAssignment, mShards /* totalShards */);
             OptionCopier.copyOptionsNoThrow(this, ctsTest);
@@ -964,8 +956,7 @@
      * Exposed for unit testing
      */
     ITestPackageRepo createTestCaseRepo() {
-        return new TestPackageRepo(mCtsBuild.getTestCasesDir(), AbiUtils.getAbisSupportedByCts(),
-                mIncludeKnownFailures);
+        return new TestPackageRepo(mCtsBuild.getTestCasesDir(), mIncludeKnownFailures);
     }
 
     /**
@@ -986,7 +977,7 @@
      */
     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);
@@ -1057,10 +1048,10 @@
     /**
      * Forward the digest and package name to the listener as a metric
      *
-     * @param listener
+     * @param listener Handles test results
      */
     private static void forwardPackageDetails(ITestPackageDef def, ITestInvocationListener listener) {
-        Map<String, String> metrics = new HashMap<String, String>(3);
+        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 e925c91..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
@@ -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/ResultFilter.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/ResultFilter.java
index 67a0f29..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;
 
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 9389816..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,7 +451,7 @@
      * @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));
         }
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 c1f168d..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.d(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/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 b6604e5..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;
 
 /**
@@ -81,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);
@@ -124,7 +126,7 @@
      */
     @SuppressWarnings("unchecked")
     public void testRun_plan() throws DeviceNotAvailableException, ParseException {
-        setParsePlanExceptations();
+        setParsePlanExpectations();
 
         setCreateAndRunTestExpectations();
 
@@ -139,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();
 
@@ -153,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());
@@ -219,7 +232,7 @@
     public void testRun_excludedPackage() throws DeviceNotAvailableException, ParseException {
         mCtsTest.setPlanName(PLAN_NAME);
         mMockPlan.parse((InputStream) EasyMock.anyObject());
-        EasyMock.expect(mMockPlan.getTestNames()).andReturn(NAMES);
+        EasyMock.expect(mMockPlan.getTestIds()).andReturn(IDS);
 
         mCtsTest.addExcludedPackageName(PACKAGE_NAME);
 
@@ -234,7 +247,7 @@
      */
     public void testRun_continueSession() throws DeviceNotAvailableException {
         mCtsTest.setContinueSessionId(1);
-        EasyMock.expect(mMockPlan.getTestNames()).andReturn(NAMES);
+        EasyMock.expect(mMockPlan.getTestIds()).andReturn(IDS);
         TestFilter filter = new TestFilter();
         EasyMock.expect(mMockPlan.getTestFilter(ID)).andReturn(filter);
 
@@ -250,10 +263,10 @@
     /**
      * 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.getTestNames()).andReturn(NAMES);
+        EasyMock.expect(mMockPlan.getTestIds()).andReturn(IDS);
         TestFilter filter = new TestFilter();
         EasyMock.expect(mMockPlan.getTestFilter(ID)).andReturn(filter);
         mMockPackageDef.setTestFilter(filter);
@@ -265,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(TEST_IDENTIFIER_LIST);
+        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());
     }